src/jdk/nashorn/internal/objects/NativeDate.java

Wed, 25 Mar 2015 14:36:22 +0530

author
sundar
date
Wed, 25 Mar 2015 14:36:22 +0530
changeset 1267
e597c5975dac
parent 1251
85a6a7545dbe
child 1490
d85f981c8cf8
child 1721
bfc671539e50
permissions
-rw-r--r--

8012190: Global scope should be initialized lazily
Reviewed-by: lagergren, hannesw, attila

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.objects;
jlaskey@3 27
jlaskey@3 28 import static java.lang.Double.NaN;
jlaskey@3 29 import static java.lang.Double.isInfinite;
jlaskey@3 30 import static java.lang.Double.isNaN;
jlaskey@3 31 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
jlaskey@3 32 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
attila@1251 33
jlaskey@3 34 import java.util.Locale;
jlaskey@3 35 import java.util.TimeZone;
sundar@489 36 import java.util.concurrent.Callable;
jlaskey@3 37 import jdk.nashorn.internal.objects.annotations.Attribute;
jlaskey@3 38 import jdk.nashorn.internal.objects.annotations.Constructor;
jlaskey@3 39 import jdk.nashorn.internal.objects.annotations.Function;
jlaskey@3 40 import jdk.nashorn.internal.objects.annotations.ScriptClass;
lagergren@1028 41 import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
jlaskey@3 42 import jdk.nashorn.internal.objects.annotations.Where;
sundar@309 43 import jdk.nashorn.internal.parser.DateParser;
jlaskey@3 44 import jdk.nashorn.internal.runtime.JSType;
hannesw@380 45 import jdk.nashorn.internal.runtime.PropertyMap;
sundar@118 46 import jdk.nashorn.internal.runtime.ScriptEnvironment;
jlaskey@3 47 import jdk.nashorn.internal.runtime.ScriptObject;
jlaskey@3 48 import jdk.nashorn.internal.runtime.ScriptRuntime;
sundar@459 49 import jdk.nashorn.internal.runtime.linker.Bootstrap;
jlaskey@3 50 import jdk.nashorn.internal.runtime.linker.InvokeByName;
jlaskey@3 51
jlaskey@3 52 /**
jlaskey@3 53 * ECMA 15.9 Date Objects
jlaskey@3 54 *
jlaskey@3 55 */
jlaskey@3 56 @ScriptClass("Date")
jlaskey@3 57 public final class NativeDate extends ScriptObject {
jlaskey@3 58
jlaskey@3 59 private static final String INVALID_DATE = "Invalid Date";
jlaskey@3 60
jlaskey@3 61 private static final int YEAR = 0;
jlaskey@3 62 private static final int MONTH = 1;
jlaskey@3 63 private static final int DAY = 2;
jlaskey@3 64 private static final int HOUR = 3;
jlaskey@3 65 private static final int MINUTE = 4;
jlaskey@3 66 private static final int SECOND = 5;
jlaskey@3 67 private static final int MILLISECOND = 6;
jlaskey@3 68
jlaskey@3 69 private static final int FORMAT_DATE_TIME = 0;
jlaskey@3 70 private static final int FORMAT_DATE = 1;
jlaskey@3 71 private static final int FORMAT_TIME = 2;
jlaskey@3 72 private static final int FORMAT_LOCAL_DATE_TIME = 3;
jlaskey@3 73 private static final int FORMAT_LOCAL_DATE = 4;
jlaskey@3 74 private static final int FORMAT_LOCAL_TIME = 5;
jlaskey@3 75
jlaskey@3 76 // Constants defined in ECMA 15.9.1.10
hannesw@570 77 private static final int hoursPerDay = 24;
hannesw@570 78 private static final int minutesPerHour = 60;
hannesw@570 79 private static final int secondsPerMinute = 60;
hannesw@570 80 private static final int msPerSecond = 1_000;
hannesw@570 81 private static final int msPerMinute = 60_000;
jlaskey@3 82 private static final double msPerHour = 3_600_000;
jlaskey@3 83 private static final double msPerDay = 86_400_000;
jlaskey@3 84
jlaskey@3 85 private static int[][] firstDayInMonth = {
jlaskey@3 86 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, // normal year
jlaskey@3 87 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} // leap year
jlaskey@3 88 };
jlaskey@3 89
jlaskey@3 90 private static String[] weekDays = {
jlaskey@3 91 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
jlaskey@3 92 };
jlaskey@3 93
jlaskey@3 94 private static String[] months = {
jlaskey@3 95 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
jlaskey@3 96 };
jlaskey@3 97
sundar@489 98 private static final Object TO_ISO_STRING = new Object();
sundar@489 99
sundar@489 100 private static InvokeByName getTO_ISO_STRING() {
sundar@489 101 return Global.instance().getInvokeByName(TO_ISO_STRING,
sundar@489 102 new Callable<InvokeByName>() {
sundar@489 103 @Override
sundar@489 104 public InvokeByName call() {
sundar@489 105 return new InvokeByName("toISOString", ScriptObject.class, Object.class, Object.class);
sundar@489 106 }
sundar@489 107 });
sundar@489 108 }
jlaskey@3 109
jlaskey@3 110 private double time;
jlaskey@3 111 private final TimeZone timezone;
jlaskey@3 112
hannesw@380 113 // initialized by nasgen
hannesw@380 114 private static PropertyMap $nasgenmap$;
hannesw@380 115
sundar@414 116 private NativeDate(final double time, final ScriptObject proto, final PropertyMap map) {
sundar@414 117 super(proto, map);
sundar@118 118 final ScriptEnvironment env = Global.getEnv();
jlaskey@3 119
jlaskey@3 120 this.time = time;
sundar@118 121 this.timezone = env._timezone;
jlaskey@3 122 }
jlaskey@3 123
sundar@1267 124 NativeDate(final double time, final ScriptObject proto) {
sundar@1267 125 this(time, proto, $nasgenmap$);
sundar@1267 126 }
sundar@1267 127
sundar@414 128 NativeDate(final double time, final Global global) {
sundar@771 129 this(time, global.getDatePrototype(), $nasgenmap$);
sundar@414 130 }
sundar@414 131
sundar@414 132 private NativeDate (final double time) {
sundar@414 133 this(time, Global.instance());
sundar@414 134 }
sundar@414 135
sundar@414 136 private NativeDate() {
sundar@414 137 this(System.currentTimeMillis());
sundar@414 138 }
sundar@414 139
jlaskey@3 140 @Override
jlaskey@3 141 public String getClassName() {
jlaskey@3 142 return "Date";
jlaskey@3 143 }
jlaskey@3 144
jlaskey@3 145 // ECMA 8.12.8 [[DefaultValue]] (hint)
jlaskey@3 146 @Override
jlaskey@3 147 public Object getDefaultValue(final Class<?> hint) {
jlaskey@3 148 // When the [[DefaultValue]] internal method of O is called with no hint,
jlaskey@3 149 // then it behaves as if the hint were Number, unless O is a Date object
jlaskey@3 150 // in which case it behaves as if the hint were String.
jlaskey@3 151 return super.getDefaultValue(hint == null ? String.class : hint);
jlaskey@3 152 }
jlaskey@3 153
jlaskey@3 154 /**
jlaskey@3 155 * Constructor - ECMA 15.9.3.1 new Date
jlaskey@3 156 *
jlaskey@3 157 * @param isNew is this Date constructed with the new operator
jlaskey@3 158 * @param self self references
jlaskey@3 159 * @return Date representing now
jlaskey@3 160 */
lagergren@1028 161 @SpecializedFunction(isConstructor=true)
jlaskey@3 162 public static Object construct(final boolean isNew, final Object self) {
jlaskey@3 163 final NativeDate result = new NativeDate();
jlaskey@3 164 return isNew ? result : toStringImpl(result, FORMAT_DATE_TIME);
jlaskey@3 165 }
jlaskey@3 166
jlaskey@3 167 /**
jlaskey@3 168 * Constructor - ECMA 15.9.3.1 new Date (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )
jlaskey@3 169 *
jlaskey@3 170 * @param isNew is this Date constructed with the new operator
jlaskey@3 171 * @param self self reference
jlaskey@3 172 * @param args arguments
jlaskey@3 173 * @return new Date
jlaskey@3 174 */
jlaskey@3 175 @Constructor(arity = 7)
jlaskey@3 176 public static Object construct(final boolean isNew, final Object self, final Object... args) {
sundar@414 177 if (! isNew) {
sundar@414 178 return toStringImpl(new NativeDate(), FORMAT_DATE_TIME);
sundar@414 179 }
sundar@414 180
jlaskey@3 181 NativeDate result;
jlaskey@3 182 switch (args.length) {
jlaskey@3 183 case 0:
jlaskey@3 184 result = new NativeDate();
jlaskey@3 185 break;
jlaskey@3 186
jlaskey@3 187 case 1:
jlaskey@3 188 double num;
jlaskey@3 189 final Object arg = JSType.toPrimitive(args[0]);
attila@1251 190 if (JSType.isString(arg)) {
jlaskey@3 191 num = parseDateString(arg.toString());
jlaskey@3 192 } else {
jlaskey@3 193 num = timeClip(JSType.toNumber(args[0]));
jlaskey@3 194 }
jlaskey@3 195 result = new NativeDate(num);
jlaskey@3 196 break;
jlaskey@3 197
jlaskey@3 198 default:
jlaskey@3 199 result = new NativeDate(0);
jlaskey@3 200 final double[] d = convertCtorArgs(args);
jlaskey@3 201 if (d == null) {
jlaskey@3 202 result.setTime(Double.NaN);
jlaskey@3 203 } else {
jlaskey@3 204 final double time = timeClip(utc(makeDate(d), result.getTimeZone()));
jlaskey@3 205 result.setTime(time);
jlaskey@3 206 }
jlaskey@3 207 break;
jlaskey@3 208 }
jlaskey@3 209
sundar@414 210 return result;
jlaskey@3 211 }
jlaskey@3 212
jlaskey@3 213 @Override
jlaskey@3 214 public String safeToString() {
hannesw@220 215 final String str = isValidDate() ? toISOStringImpl(this) : INVALID_DATE;
hannesw@220 216 return "[Date " + str + "]";
jlaskey@3 217 }
jlaskey@3 218
jlaskey@3 219 @Override
jlaskey@3 220 public String toString() {
jlaskey@3 221 return isValidDate() ? toString(this).toString() : INVALID_DATE;
jlaskey@3 222 }
jlaskey@3 223
jlaskey@3 224 /**
jlaskey@3 225 * ECMA 15.9.4.2 Date.parse (string)
jlaskey@3 226 *
jlaskey@3 227 * @param self self reference
jlaskey@3 228 * @param string string to parse as date
jlaskey@3 229 * @return Date interpreted from the string, or NaN for illegal values
jlaskey@3 230 */
jlaskey@3 231 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
sundar@774 232 public static double parse(final Object self, final Object string) {
jlaskey@3 233 return parseDateString(JSType.toString(string));
jlaskey@3 234 }
jlaskey@3 235
jlaskey@3 236 /**
jlaskey@3 237 * ECMA 15.9.4.3 Date.UTC (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )
jlaskey@3 238 *
jlaskey@3 239 * @param self self reference
jlaskey@3 240 * @param args mandatory args are year, month. Optional are date, hours, minutes, seconds and milliseconds
jlaskey@3 241 * @return a time clip according to the ECMA specification
jlaskey@3 242 */
jlaskey@3 243 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 7, where = Where.CONSTRUCTOR)
sundar@774 244 public static double UTC(final Object self, final Object... args) {
jlaskey@3 245 final NativeDate nd = new NativeDate(0);
jlaskey@3 246 final double[] d = convertCtorArgs(args);
jlaskey@3 247 final double time = d == null ? Double.NaN : timeClip(makeDate(d));
jlaskey@3 248 nd.setTime(time);
jlaskey@3 249 return time;
jlaskey@3 250 }
jlaskey@3 251
jlaskey@3 252 /**
jlaskey@3 253 * ECMA 15.9.4.4 Date.now ( )
jlaskey@3 254 *
jlaskey@3 255 * @param self self reference
jlaskey@3 256 * @return a Date that points to the current moment in time
jlaskey@3 257 */
jlaskey@3 258 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
sundar@774 259 public static long now(final Object self) {
sundar@774 260 return System.currentTimeMillis();
jlaskey@3 261 }
jlaskey@3 262
jlaskey@3 263 /**
jlaskey@3 264 * ECMA 15.9.5.2 Date.prototype.toString ( )
jlaskey@3 265 *
jlaskey@3 266 * @param self self reference
jlaskey@3 267 * @return string value that represents the Date in the current time zone
jlaskey@3 268 */
jlaskey@3 269 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 270 public static String toString(final Object self) {
jlaskey@3 271 return toStringImpl(self, FORMAT_DATE_TIME);
jlaskey@3 272 }
jlaskey@3 273
jlaskey@3 274 /**
jlaskey@3 275 * ECMA 15.9.5.3 Date.prototype.toDateString ( )
jlaskey@3 276 *
jlaskey@3 277 * @param self self reference
jlaskey@3 278 * @return string value with the "date" part of the Date in the current time zone
jlaskey@3 279 */
jlaskey@3 280 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 281 public static String toDateString(final Object self) {
jlaskey@3 282 return toStringImpl(self, FORMAT_DATE);
jlaskey@3 283 }
jlaskey@3 284
jlaskey@3 285 /**
jlaskey@3 286 * ECMA 15.9.5.4 Date.prototype.toTimeString ( )
jlaskey@3 287 *
jlaskey@3 288 * @param self self reference
jlaskey@3 289 * @return string value with "time" part of Date in the current time zone
jlaskey@3 290 */
jlaskey@3 291 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 292 public static String toTimeString(final Object self) {
jlaskey@3 293 return toStringImpl(self, FORMAT_TIME);
jlaskey@3 294 }
jlaskey@3 295
jlaskey@3 296 /**
jlaskey@3 297 * ECMA 15.9.5.5 Date.prototype.toLocaleString ( )
jlaskey@3 298 *
jlaskey@3 299 * @param self self reference
jlaskey@3 300 * @return string value that represents the Data in the current time zone and locale
jlaskey@3 301 */
jlaskey@3 302 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 303 public static String toLocaleString(final Object self) {
jlaskey@3 304 return toStringImpl(self, FORMAT_LOCAL_DATE_TIME);
jlaskey@3 305 }
jlaskey@3 306
jlaskey@3 307 /**
jlaskey@3 308 * ECMA 15.9.5.6 Date.prototype.toLocaleDateString ( )
jlaskey@3 309 *
jlaskey@3 310 * @param self self reference
jlaskey@3 311 * @return string value with the "date" part of the Date in the current time zone and locale
jlaskey@3 312 */
jlaskey@3 313 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 314 public static String toLocaleDateString(final Object self) {
jlaskey@3 315 return toStringImpl(self, FORMAT_LOCAL_DATE);
jlaskey@3 316 }
jlaskey@3 317
jlaskey@3 318 /**
jlaskey@3 319 * ECMA 15.9.5.7 Date.prototype.toLocaleTimeString ( )
jlaskey@3 320 *
jlaskey@3 321 * @param self self reference
jlaskey@3 322 * @return string value with the "time" part of Date in the current time zone and locale
jlaskey@3 323 */
jlaskey@3 324 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 325 public static String toLocaleTimeString(final Object self) {
jlaskey@3 326 return toStringImpl(self, FORMAT_LOCAL_TIME);
jlaskey@3 327 }
jlaskey@3 328
jlaskey@3 329 /**
jlaskey@3 330 * ECMA 15.9.5.8 Date.prototype.valueOf ( )
jlaskey@3 331 *
jlaskey@3 332 * @param self self reference
jlaskey@3 333 * @return valueOf - a number which is this time value
jlaskey@3 334 */
jlaskey@3 335 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 336 public static double valueOf(final Object self) {
jlaskey@3 337 final NativeDate nd = getNativeDate(self);
jlaskey@3 338 return (nd != null) ? nd.getTime() : Double.NaN;
jlaskey@3 339 }
jlaskey@3 340
jlaskey@3 341 /**
jlaskey@3 342 * ECMA 15.9.5.9 Date.prototype.getTime ( )
jlaskey@3 343 *
jlaskey@3 344 * @param self self reference
jlaskey@3 345 * @return time
jlaskey@3 346 */
jlaskey@3 347 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 348 public static double getTime(final Object self) {
jlaskey@3 349 final NativeDate nd = getNativeDate(self);
jlaskey@3 350 return (nd != null) ? nd.getTime() : Double.NaN;
jlaskey@3 351 }
jlaskey@3 352
jlaskey@3 353 /**
jlaskey@3 354 * ECMA 15.9.5.10 Date.prototype.getFullYear ( )
jlaskey@3 355 *
jlaskey@3 356 * @param self self reference
jlaskey@3 357 * @return full year
jlaskey@3 358 */
jlaskey@3 359 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 360 public static Object getFullYear(final Object self) {
jlaskey@3 361 return getField(self, YEAR);
jlaskey@3 362 }
jlaskey@3 363
jlaskey@3 364 /**
jlaskey@3 365 * ECMA 15.9.5.11 Date.prototype.getUTCFullYear( )
jlaskey@3 366 *
jlaskey@3 367 * @param self self reference
jlaskey@3 368 * @return UTC full year
jlaskey@3 369 */
jlaskey@3 370 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 371 public static double getUTCFullYear(final Object self) {
jlaskey@3 372 return getUTCField(self, YEAR);
jlaskey@3 373 }
jlaskey@3 374
jlaskey@3 375 /**
jlaskey@3 376 * B.2.4 Date.prototype.getYear ( )
jlaskey@3 377 *
jlaskey@3 378 * @param self self reference
jlaskey@3 379 * @return year
jlaskey@3 380 */
jlaskey@3 381 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 382 public static double getYear(final Object self) {
jlaskey@3 383 final NativeDate nd = getNativeDate(self);
jlaskey@3 384 return (nd != null && nd.isValidDate()) ? (yearFromTime(nd.getLocalTime()) - 1900) : Double.NaN;
jlaskey@3 385 }
jlaskey@3 386
jlaskey@3 387 /**
jlaskey@3 388 * ECMA 15.9.5.12 Date.prototype.getMonth ( )
jlaskey@3 389 *
jlaskey@3 390 * @param self self reference
jlaskey@3 391 * @return month
jlaskey@3 392 */
jlaskey@3 393 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 394 public static double getMonth(final Object self) {
jlaskey@3 395 return getField(self, MONTH);
jlaskey@3 396 }
jlaskey@3 397
jlaskey@3 398 /**
jlaskey@3 399 * ECMA 15.9.5.13 Date.prototype.getUTCMonth ( )
jlaskey@3 400 *
jlaskey@3 401 * @param self self reference
jlaskey@3 402 * @return UTC month
jlaskey@3 403 */
jlaskey@3 404 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 405 public static double getUTCMonth(final Object self) {
jlaskey@3 406 return getUTCField(self, MONTH);
jlaskey@3 407 }
jlaskey@3 408
jlaskey@3 409 /**
jlaskey@3 410 * ECMA 15.9.5.14 Date.prototype.getDate ( )
jlaskey@3 411 *
jlaskey@3 412 * @param self self reference
jlaskey@3 413 * @return date
jlaskey@3 414 */
jlaskey@3 415 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 416 public static double getDate(final Object self) {
jlaskey@3 417 return getField(self, DAY);
jlaskey@3 418 }
jlaskey@3 419
jlaskey@3 420 /**
jlaskey@3 421 * ECMA 15.9.5.15 Date.prototype.getUTCDate ( )
jlaskey@3 422 *
jlaskey@3 423 * @param self self reference
jlaskey@3 424 * @return UTC Date
jlaskey@3 425 */
jlaskey@3 426 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 427 public static double getUTCDate(final Object self) {
jlaskey@3 428 return getUTCField(self, DAY);
jlaskey@3 429 }
jlaskey@3 430
jlaskey@3 431 /**
jlaskey@3 432 * ECMA 15.9.5.16 Date.prototype.getDay ( )
jlaskey@3 433 *
jlaskey@3 434 * @param self self reference
jlaskey@3 435 * @return day
jlaskey@3 436 */
jlaskey@3 437 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 438 public static double getDay(final Object self) {
jlaskey@3 439 final NativeDate nd = getNativeDate(self);
jlaskey@3 440 return (nd != null && nd.isValidDate()) ? weekDay(nd.getLocalTime()) : Double.NaN;
jlaskey@3 441 }
jlaskey@3 442
jlaskey@3 443 /**
jlaskey@3 444 * ECMA 15.9.5.17 Date.prototype.getUTCDay ( )
jlaskey@3 445 *
jlaskey@3 446 * @param self self reference
jlaskey@3 447 * @return UTC day
jlaskey@3 448 */
jlaskey@3 449 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 450 public static double getUTCDay(final Object self) {
jlaskey@3 451 final NativeDate nd = getNativeDate(self);
jlaskey@3 452 return (nd != null && nd.isValidDate()) ? weekDay(nd.getTime()) : Double.NaN;
jlaskey@3 453 }
jlaskey@3 454
jlaskey@3 455 /**
jlaskey@3 456 * ECMA 15.9.5.18 Date.prototype.getHours ( )
jlaskey@3 457 *
jlaskey@3 458 * @param self self reference
jlaskey@3 459 * @return hours
jlaskey@3 460 */
jlaskey@3 461 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 462 public static double getHours(final Object self) {
jlaskey@3 463 return getField(self, HOUR);
jlaskey@3 464 }
jlaskey@3 465
jlaskey@3 466 /**
jlaskey@3 467 * ECMA 15.9.5.19 Date.prototype.getUTCHours ( )
jlaskey@3 468 *
jlaskey@3 469 * @param self self reference
jlaskey@3 470 * @return UTC hours
jlaskey@3 471 */
jlaskey@3 472 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 473 public static double getUTCHours(final Object self) {
jlaskey@3 474 return getUTCField(self, HOUR);
jlaskey@3 475 }
jlaskey@3 476
jlaskey@3 477 /**
jlaskey@3 478 * ECMA 15.9.5.20 Date.prototype.getMinutes ( )
jlaskey@3 479 *
jlaskey@3 480 * @param self self reference
jlaskey@3 481 * @return minutes
jlaskey@3 482 */
jlaskey@3 483 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 484 public static double getMinutes(final Object self) {
jlaskey@3 485 return getField(self, MINUTE);
jlaskey@3 486 }
jlaskey@3 487
jlaskey@3 488 /**
jlaskey@3 489 * ECMA 15.9.5.21 Date.prototype.getUTCMinutes ( )
jlaskey@3 490 *
jlaskey@3 491 * @param self self reference
jlaskey@3 492 * @return UTC minutes
jlaskey@3 493 */
jlaskey@3 494 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 495 public static double getUTCMinutes(final Object self) {
jlaskey@3 496 return getUTCField(self, MINUTE);
jlaskey@3 497 }
jlaskey@3 498
jlaskey@3 499 /**
jlaskey@3 500 * ECMA 15.9.5.22 Date.prototype.getSeconds ( )
jlaskey@3 501 *
jlaskey@3 502 * @param self self reference
jlaskey@3 503 * @return seconds
jlaskey@3 504 */
jlaskey@3 505 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 506 public static double getSeconds(final Object self) {
jlaskey@3 507 return getField(self, SECOND);
jlaskey@3 508 }
jlaskey@3 509
jlaskey@3 510 /**
jlaskey@3 511 * ECMA 15.9.5.23 Date.prototype.getUTCSeconds ( )
jlaskey@3 512 *
jlaskey@3 513 * @param self self reference
jlaskey@3 514 * @return UTC seconds
jlaskey@3 515 */
jlaskey@3 516 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 517 public static double getUTCSeconds(final Object self) {
jlaskey@3 518 return getUTCField(self, SECOND);
jlaskey@3 519 }
jlaskey@3 520
jlaskey@3 521 /**
jlaskey@3 522 * ECMA 15.9.5.24 Date.prototype.getMilliseconds ( )
jlaskey@3 523 *
jlaskey@3 524 * @param self self reference
jlaskey@3 525 * @return milliseconds
jlaskey@3 526 */
jlaskey@3 527 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 528 public static double getMilliseconds(final Object self) {
jlaskey@3 529 return getField(self, MILLISECOND);
jlaskey@3 530 }
jlaskey@3 531
jlaskey@3 532 /**
jlaskey@3 533 * ECMA 15.9.5.25 Date.prototype.getUTCMilliseconds ( )
jlaskey@3 534 *
jlaskey@3 535 * @param self self reference
jlaskey@3 536 * @return UTC milliseconds
jlaskey@3 537 */
jlaskey@3 538 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 539 public static double getUTCMilliseconds(final Object self) {
jlaskey@3 540 return getUTCField(self, MILLISECOND);
jlaskey@3 541 }
jlaskey@3 542
jlaskey@3 543 /**
jlaskey@3 544 * ECMA 15.9.5.26 Date.prototype.getTimezoneOffset ( )
jlaskey@3 545 *
jlaskey@3 546 * @param self self reference
jlaskey@3 547 * @return time zone offset or NaN if N/A
jlaskey@3 548 */
jlaskey@3 549 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 550 public static double getTimezoneOffset(final Object self) {
jlaskey@3 551 final NativeDate nd = getNativeDate(self);
sundar@229 552 if (nd != null && nd.isValidDate()) {
jlaskey@3 553 final long msec = (long) nd.getTime();
jlaskey@3 554 return - nd.getTimeZone().getOffset(msec) / msPerMinute;
jlaskey@3 555 }
jlaskey@3 556 return Double.NaN;
jlaskey@3 557 }
jlaskey@3 558
jlaskey@3 559 /**
jlaskey@3 560 * ECMA 15.9.5.27 Date.prototype.setTime (time)
jlaskey@3 561 *
jlaskey@3 562 * @param self self reference
jlaskey@3 563 * @param time time
jlaskey@3 564 * @return time
jlaskey@3 565 */
jlaskey@3 566 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 567 public static double setTime(final Object self, final Object time) {
sundar@229 568 final NativeDate nd = getNativeDate(self);
jlaskey@3 569 final double num = timeClip(JSType.toNumber(time));
jlaskey@3 570 nd.setTime(num);
jlaskey@3 571 return num;
jlaskey@3 572 }
jlaskey@3 573
jlaskey@3 574 /**
jlaskey@3 575 * ECMA 15.9.5.28 Date.prototype.setMilliseconds (ms)
jlaskey@3 576 *
jlaskey@3 577 * @param self self reference
jlaskey@3 578 * @param args milliseconds
jlaskey@3 579 * @return time
jlaskey@3 580 */
jlaskey@3 581 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
sundar@774 582 public static double setMilliseconds(final Object self, final Object... args) {
jlaskey@3 583 final NativeDate nd = getNativeDate(self);
sundar@229 584 setFields(nd, MILLISECOND, args, true);
jlaskey@3 585 return nd.getTime();
jlaskey@3 586 }
jlaskey@3 587
jlaskey@3 588 /**
jlaskey@3 589 * ECMA 15.9.5.29 Date.prototype.setUTCMilliseconds (ms)
jlaskey@3 590 *
jlaskey@3 591 * @param self self reference
jlaskey@3 592 * @param args utc milliseconds
jlaskey@3 593 * @return time
jlaskey@3 594 */
jlaskey@3 595 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
sundar@774 596 public static double setUTCMilliseconds(final Object self, final Object... args) {
jlaskey@3 597 final NativeDate nd = getNativeDate(self);
sundar@229 598 setFields(nd, MILLISECOND, args, false);
jlaskey@3 599 return nd.getTime();
jlaskey@3 600 }
jlaskey@3 601
jlaskey@3 602 /**
jlaskey@3 603 * ECMA 15.9.5.30 Date.prototype.setSeconds (sec [, ms ] )
jlaskey@3 604 *
jlaskey@3 605 * @param self self reference
jlaskey@3 606 * @param args seconds (milliseconds optional second argument)
jlaskey@3 607 * @return time
jlaskey@3 608 */
jlaskey@3 609 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
sundar@774 610 public static double setSeconds(final Object self, final Object... args) {
jlaskey@3 611 final NativeDate nd = getNativeDate(self);
sundar@229 612 setFields(nd, SECOND, args, true);
jlaskey@3 613 return nd.getTime();
jlaskey@3 614 }
jlaskey@3 615
jlaskey@3 616 /**
jlaskey@3 617 * ECMA 15.9.5.31 Date.prototype.setUTCSeconds (sec [, ms ] )
jlaskey@3 618 *
jlaskey@3 619 * @param self self reference
jlaskey@3 620 * @param args UTC seconds (milliseconds optional second argument)
jlaskey@3 621 * @return time
jlaskey@3 622 */
jlaskey@3 623 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
sundar@774 624 public static double setUTCSeconds(final Object self, final Object... args) {
jlaskey@3 625 final NativeDate nd = getNativeDate(self);
sundar@229 626 setFields(nd, SECOND, args, false);
jlaskey@3 627 return nd.getTime();
jlaskey@3 628 }
jlaskey@3 629
jlaskey@3 630 /**
jlaskey@3 631 * ECMA 15.9.5.32 Date.prototype.setMinutes (min [, sec [, ms ] ] )
jlaskey@3 632 *
jlaskey@3 633 * @param self self reference
jlaskey@3 634 * @param args minutes (seconds and milliseconds are optional second and third arguments)
jlaskey@3 635 * @return time
jlaskey@3 636 */
jlaskey@3 637 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3)
sundar@774 638 public static double setMinutes(final Object self, final Object... args) {
jlaskey@3 639 final NativeDate nd = getNativeDate(self);
sundar@229 640 setFields(nd, MINUTE, args, true);
jlaskey@3 641 return nd.getTime();
jlaskey@3 642 }
jlaskey@3 643
jlaskey@3 644 /**
jlaskey@3 645 * ECMA 15.9.5.33 Date.prototype.setUTCMinutes (min [, sec [, ms ] ] )
jlaskey@3 646 *
jlaskey@3 647 * @param self self reference
jlaskey@3 648 * @param args minutes (seconds and milliseconds are optional second and third arguments)
jlaskey@3 649 * @return time
jlaskey@3 650 */
jlaskey@3 651 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3)
sundar@774 652 public static double setUTCMinutes(final Object self, final Object... args) {
jlaskey@3 653 final NativeDate nd = getNativeDate(self);
sundar@229 654 setFields(nd, MINUTE, args, false);
jlaskey@3 655 return nd.getTime();
jlaskey@3 656 }
jlaskey@3 657
jlaskey@3 658 /**
jlaskey@3 659 * ECMA 15.9.5.34 Date.prototype.setHours (hour [, min [, sec [, ms ] ] ] )
jlaskey@3 660 *
jlaskey@3 661 * @param self self reference
jlaskey@3 662 * @param args hour (optional arguments after are minutes, seconds, milliseconds)
jlaskey@3 663 * @return time
jlaskey@3 664 */
jlaskey@3 665 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4)
sundar@774 666 public static double setHours(final Object self, final Object... args) {
jlaskey@3 667 final NativeDate nd = getNativeDate(self);
sundar@229 668 setFields(nd, HOUR, args, true);
jlaskey@3 669 return nd.getTime();
jlaskey@3 670 }
jlaskey@3 671
jlaskey@3 672 /**
jlaskey@3 673 * ECMA 15.9.5.35 Date.prototype.setUTCHours (hour [, min [, sec [, ms ] ] ] )
jlaskey@3 674 *
jlaskey@3 675 * @param self self reference
jlaskey@3 676 * @param args hour (optional arguments after are minutes, seconds, milliseconds)
jlaskey@3 677 * @return time
jlaskey@3 678 */
jlaskey@3 679 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4)
sundar@774 680 public static double setUTCHours(final Object self, final Object... args) {
jlaskey@3 681 final NativeDate nd = getNativeDate(self);
sundar@229 682 setFields(nd, HOUR, args, false);
jlaskey@3 683 return nd.getTime();
jlaskey@3 684 }
jlaskey@3 685
jlaskey@3 686 /**
jlaskey@3 687 * ECMA 15.9.5.36 Date.prototype.setDate (date)
jlaskey@3 688 *
jlaskey@3 689 * @param self self reference
jlaskey@3 690 * @param args date
jlaskey@3 691 * @return time
jlaskey@3 692 */
jlaskey@3 693 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
sundar@774 694 public static double setDate(final Object self, final Object... args) {
jlaskey@3 695 final NativeDate nd = getNativeDate(self);
sundar@229 696 setFields(nd, DAY, args, true);
jlaskey@3 697 return nd.getTime();
jlaskey@3 698 }
jlaskey@3 699
jlaskey@3 700 /**
jlaskey@3 701 * ECMA 15.9.5.37 Date.prototype.setUTCDate (date)
jlaskey@3 702 *
jlaskey@3 703 * @param self self reference
jlaskey@3 704 * @param args UTC date
jlaskey@3 705 * @return time
jlaskey@3 706 */
jlaskey@3 707 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
sundar@774 708 public static double setUTCDate(final Object self, final Object... args) {
jlaskey@3 709 final NativeDate nd = getNativeDate(self);
sundar@229 710 setFields(nd, DAY, args, false);
jlaskey@3 711 return nd.getTime();
jlaskey@3 712 }
jlaskey@3 713
jlaskey@3 714 /**
jlaskey@3 715 * ECMA 15.9.5.38 Date.prototype.setMonth (month [, date ] )
jlaskey@3 716 *
jlaskey@3 717 * @param self self reference
jlaskey@3 718 * @param args month (optional second argument is date)
jlaskey@3 719 * @return time
jlaskey@3 720 */
jlaskey@3 721 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
sundar@774 722 public static double setMonth(final Object self, final Object... args) {
jlaskey@3 723 final NativeDate nd = getNativeDate(self);
sundar@229 724 setFields(nd, MONTH, args, true);
jlaskey@3 725 return nd.getTime();
jlaskey@3 726 }
jlaskey@3 727
jlaskey@3 728 /**
jlaskey@3 729 * ECMA 15.9.5.39 Date.prototype.setUTCMonth (month [, date ] )
jlaskey@3 730 *
jlaskey@3 731 * @param self self reference
jlaskey@3 732 * @param args UTC month (optional second argument is date)
jlaskey@3 733 * @return time
jlaskey@3 734 */
jlaskey@3 735 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
sundar@774 736 public static double setUTCMonth(final Object self, final Object... args) {
jlaskey@3 737 final NativeDate nd = ensureNativeDate(self);
sundar@229 738 setFields(nd, MONTH, args, false);
jlaskey@3 739 return nd.getTime();
jlaskey@3 740 }
jlaskey@3 741
jlaskey@3 742 /**
jlaskey@3 743 * ECMA 15.9.5.40 Date.prototype.setFullYear (year [, month [, date ] ] )
jlaskey@3 744 *
jlaskey@3 745 * @param self self reference
jlaskey@3 746 * @param args year (optional second and third arguments are month and date)
jlaskey@3 747 * @return time
jlaskey@3 748 */
jlaskey@3 749 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3)
sundar@774 750 public static double setFullYear(final Object self, final Object... args) {
jlaskey@3 751 final NativeDate nd = ensureNativeDate(self);
jlaskey@3 752 if (nd.isValidDate()) {
jlaskey@3 753 setFields(nd, YEAR, args, true);
jlaskey@3 754 } else {
jlaskey@3 755 final double[] d = convertArgs(args, 0, YEAR, YEAR, 3);
sundar@229 756 if (d != null) {
sundar@229 757 nd.setTime(timeClip(utc(makeDate(makeDay(d[0], d[1], d[2]), 0), nd.getTimeZone())));
sundar@229 758 } else {
sundar@229 759 nd.setTime(NaN);
sundar@229 760 }
jlaskey@3 761 }
jlaskey@3 762 return nd.getTime();
jlaskey@3 763 }
jlaskey@3 764
jlaskey@3 765 /**
jlaskey@3 766 * ECMA 15.9.5.41 Date.prototype.setUTCFullYear (year [, month [, date ] ] )
jlaskey@3 767 *
jlaskey@3 768 * @param self self reference
jlaskey@3 769 * @param args UTC full year (optional second and third arguments are month and date)
jlaskey@3 770 * @return time
jlaskey@3 771 */
jlaskey@3 772 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3)
sundar@774 773 public static double setUTCFullYear(final Object self, final Object... args) {
jlaskey@3 774 final NativeDate nd = ensureNativeDate(self);
jlaskey@3 775 if (nd.isValidDate()) {
jlaskey@3 776 setFields(nd, YEAR, args, false);
jlaskey@3 777 } else {
jlaskey@3 778 final double[] d = convertArgs(args, 0, YEAR, YEAR, 3);
jlaskey@3 779 nd.setTime(timeClip(makeDate(makeDay(d[0], d[1], d[2]), 0)));
jlaskey@3 780 }
jlaskey@3 781 return nd.getTime();
jlaskey@3 782 }
jlaskey@3 783
jlaskey@3 784 /**
jlaskey@3 785 * ECMA B.2.5 Date.prototype.setYear (year)
jlaskey@3 786 *
jlaskey@3 787 * @param self self reference
jlaskey@3 788 * @param year year
jlaskey@3 789 * @return NativeDate
jlaskey@3 790 */
jlaskey@3 791 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 792 public static double setYear(final Object self, final Object year) {
jlaskey@3 793 final NativeDate nd = getNativeDate(self);
jlaskey@3 794 if (isNaN(nd.getTime())) {
sundar@229 795 nd.setTime(utc(0, nd.getTimeZone()));
jlaskey@3 796 }
jlaskey@3 797
jlaskey@3 798 final double yearNum = JSType.toNumber(year);
jlaskey@3 799 if (isNaN(yearNum)) {
jlaskey@3 800 nd.setTime(NaN);
sundar@229 801 return nd.getTime();
jlaskey@3 802 }
hannesw@285 803 int yearInt = (int)yearNum;
jlaskey@3 804 if (0 <= yearInt && yearInt <= 99) {
jlaskey@3 805 yearInt += 1900;
jlaskey@3 806 }
jlaskey@3 807 setFields(nd, YEAR, new Object[] {yearInt}, true);
jlaskey@3 808
sundar@229 809 return nd.getTime();
jlaskey@3 810 }
jlaskey@3 811
jlaskey@3 812 /**
jlaskey@3 813 * ECMA 15.9.5.42 Date.prototype.toUTCString ( )
jlaskey@3 814 *
jlaskey@3 815 * @param self self reference
jlaskey@3 816 * @return string representation of date
jlaskey@3 817 */
jlaskey@3 818 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 819 public static String toUTCString(final Object self) {
jlaskey@3 820 return toGMTStringImpl(self);
jlaskey@3 821 }
jlaskey@3 822
jlaskey@3 823 /**
jlaskey@3 824 * ECMA B.2.6 Date.prototype.toGMTString ( )
jlaskey@3 825 *
jlaskey@3 826 * See {@link NativeDate#toUTCString(Object)}
jlaskey@3 827 *
jlaskey@3 828 * @param self self reference
jlaskey@3 829 * @return string representation of date
jlaskey@3 830 */
jlaskey@3 831 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 832 public static String toGMTString(final Object self) {
jlaskey@3 833 return toGMTStringImpl(self);
jlaskey@3 834 }
jlaskey@3 835
jlaskey@3 836 /**
jlaskey@3 837 * ECMA 15.9.5.43 Date.prototype.toISOString ( )
jlaskey@3 838 *
jlaskey@3 839 * @param self self reference
jlaskey@3 840 * @return string representation of date
jlaskey@3 841 */
jlaskey@3 842 @Function(attributes = Attribute.NOT_ENUMERABLE)
sundar@774 843 public static String toISOString(final Object self) {
jlaskey@3 844 return toISOStringImpl(self);
jlaskey@3 845 }
jlaskey@3 846
jlaskey@3 847 /**
jlaskey@3 848 * ECMA 15.9.5.44 Date.prototype.toJSON ( key )
jlaskey@3 849 *
jlaskey@3 850 * Provides a string representation of this Date for use by {@link NativeJSON#stringify(Object, Object, Object, Object)}
jlaskey@3 851 *
jlaskey@3 852 * @param self self reference
jlaskey@3 853 * @param key ignored
jlaskey@3 854 * @return JSON representation of this date
jlaskey@3 855 */
jlaskey@3 856 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 857 public static Object toJSON(final Object self, final Object key) {
jlaskey@3 858 // NOTE: Date.prototype.toJSON is generic. Accepts other objects as well.
jlaskey@3 859 final Object selfObj = Global.toObject(self);
jlaskey@3 860 if (!(selfObj instanceof ScriptObject)) {
jlaskey@3 861 return null;
jlaskey@3 862 }
jlaskey@3 863 final ScriptObject sobj = (ScriptObject)selfObj;
jlaskey@3 864 final Object value = sobj.getDefaultValue(Number.class);
sundar@207 865 if (value instanceof Number) {
sundar@207 866 final double num = ((Number)value).doubleValue();
sundar@207 867 if (isInfinite(num) || isNaN(num)) {
sundar@207 868 return null;
sundar@207 869 }
jlaskey@3 870 }
jlaskey@3 871
jlaskey@3 872 try {
sundar@489 873 final InvokeByName toIsoString = getTO_ISO_STRING();
sundar@489 874 final Object func = toIsoString.getGetter().invokeExact(sobj);
sundar@459 875 if (Bootstrap.isCallable(func)) {
sundar@489 876 return toIsoString.getInvoker().invokeExact(func, sobj, key);
jlaskey@3 877 }
lagergren@112 878 throw typeError("not.a.function", ScriptRuntime.safeToString(func));
jlaskey@3 879 } catch (final RuntimeException | Error e) {
jlaskey@3 880 throw e;
jlaskey@3 881 } catch (final Throwable t) {
jlaskey@3 882 throw new RuntimeException(t);
jlaskey@3 883 }
jlaskey@3 884 }
jlaskey@3 885
jlaskey@3 886 // -- Internals below this point
jlaskey@3 887
jlaskey@3 888 private static double parseDateString(final String str) {
jlaskey@3 889
jlaskey@3 890 final DateParser parser = new DateParser(str);
jlaskey@3 891 if (parser.parse()) {
jlaskey@3 892 final Integer[] fields = parser.getDateFields();
jlaskey@3 893 double d = makeDate(fields);
jlaskey@3 894 if (fields[DateParser.TIMEZONE] != null) {
jlaskey@3 895 d -= fields[DateParser.TIMEZONE] * 60000;
jlaskey@3 896 } else {
sundar@118 897 d = utc(d, Global.getEnv()._timezone);
jlaskey@3 898 }
jlaskey@3 899 d = timeClip(d);
jlaskey@3 900 return d;
jlaskey@3 901 }
jlaskey@3 902
jlaskey@3 903 return Double.NaN;
jlaskey@3 904 }
jlaskey@3 905
jlaskey@3 906 private static void zeroPad(final StringBuilder sb, final int n, final int length) {
jlaskey@3 907 for (int l = 1, d = 10; l < length; l++, d *= 10) {
jlaskey@3 908 if (n < d) {
jlaskey@3 909 sb.append('0');
jlaskey@3 910 }
jlaskey@3 911 }
jlaskey@3 912 sb.append(n);
jlaskey@3 913 }
jlaskey@3 914
attila@963 915 @SuppressWarnings("fallthrough")
jlaskey@3 916 private static String toStringImpl(final Object self, final int format) {
jlaskey@3 917 final NativeDate nd = getNativeDate(self);
jlaskey@3 918
jlaskey@3 919 if (nd != null && nd.isValidDate()) {
jlaskey@3 920 final StringBuilder sb = new StringBuilder(40);
jlaskey@3 921 final double t = nd.getLocalTime();
jlaskey@3 922
jlaskey@3 923 switch (format) {
jlaskey@3 924
jlaskey@3 925 case FORMAT_DATE_TIME:
jlaskey@3 926 case FORMAT_DATE :
jlaskey@3 927 case FORMAT_LOCAL_DATE_TIME:
jlaskey@3 928 // EEE MMM dd yyyy
hannesw@570 929 sb.append(weekDays[weekDay(t)])
jlaskey@3 930 .append(' ')
hannesw@570 931 .append(months[monthFromTime(t)])
jlaskey@3 932 .append(' ');
hannesw@570 933 zeroPad(sb, dayFromTime(t), 2);
jlaskey@3 934 sb.append(' ');
hannesw@570 935 zeroPad(sb, yearFromTime(t), 4);
jlaskey@3 936 if (format == FORMAT_DATE) {
jlaskey@3 937 break;
jlaskey@3 938 }
jlaskey@3 939 sb.append(' ');
jlaskey@3 940
jlaskey@3 941 case FORMAT_TIME:
jlaskey@3 942 final TimeZone tz = nd.getTimeZone();
jlaskey@3 943 final double utcTime = nd.getTime();
jlaskey@3 944 int offset = tz.getOffset((long) utcTime) / 60000;
jlaskey@3 945 final boolean inDaylightTime = offset != tz.getRawOffset() / 60000;
jlaskey@3 946 // Convert minutes to HHmm timezone offset
jlaskey@3 947 offset = (offset / 60) * 100 + offset % 60;
jlaskey@3 948
jlaskey@3 949 // HH:mm:ss GMT+HHmm
hannesw@570 950 zeroPad(sb, hourFromTime(t), 2);
jlaskey@3 951 sb.append(':');
hannesw@570 952 zeroPad(sb, minFromTime(t), 2);
jlaskey@3 953 sb.append(':');
hannesw@570 954 zeroPad(sb, secFromTime(t), 2);
jlaskey@3 955 sb.append(" GMT")
jlaskey@3 956 .append(offset < 0 ? '-' : '+');
jlaskey@3 957 zeroPad(sb, Math.abs(offset), 4);
jlaskey@3 958 sb.append(" (")
jlaskey@3 959 .append(tz.getDisplayName(inDaylightTime, TimeZone.SHORT, Locale.US))
jlaskey@3 960 .append(')');
jlaskey@3 961 break;
jlaskey@3 962
jlaskey@3 963 case FORMAT_LOCAL_DATE:
jlaskey@3 964 // yyyy-MM-dd
hannesw@570 965 zeroPad(sb, yearFromTime(t), 4);
jlaskey@3 966 sb.append('-');
hannesw@570 967 zeroPad(sb, monthFromTime(t) + 1, 2);
jlaskey@3 968 sb.append('-');
hannesw@570 969 zeroPad(sb, dayFromTime(t), 2);
jlaskey@3 970 break;
jlaskey@3 971
jlaskey@3 972 case FORMAT_LOCAL_TIME:
jlaskey@3 973 // HH:mm:ss
hannesw@570 974 zeroPad(sb, hourFromTime(t), 2);
jlaskey@3 975 sb.append(':');
hannesw@570 976 zeroPad(sb, minFromTime(t), 2);
jlaskey@3 977 sb.append(':');
hannesw@570 978 zeroPad(sb, secFromTime(t), 2);
jlaskey@3 979 break;
jlaskey@3 980
jlaskey@3 981 default:
jlaskey@3 982 throw new IllegalArgumentException("format: " + format);
jlaskey@3 983 }
jlaskey@3 984
jlaskey@3 985 return sb.toString();
jlaskey@3 986 }
jlaskey@3 987
jlaskey@3 988 return INVALID_DATE;
jlaskey@3 989 }
jlaskey@3 990
jlaskey@3 991 private static String toGMTStringImpl(final Object self) {
jlaskey@3 992 final NativeDate nd = getNativeDate(self);
jlaskey@3 993
jlaskey@3 994 if (nd != null && nd.isValidDate()) {
jlaskey@3 995 final StringBuilder sb = new StringBuilder(29);
jlaskey@3 996 final double t = nd.getTime();
jlaskey@3 997 // EEE, dd MMM yyyy HH:mm:ss z
hannesw@570 998 sb.append(weekDays[weekDay(t)])
jlaskey@3 999 .append(", ");
hannesw@570 1000 zeroPad(sb, dayFromTime(t), 2);
jlaskey@3 1001 sb.append(' ')
hannesw@570 1002 .append(months[monthFromTime(t)])
jlaskey@3 1003 .append(' ');
hannesw@570 1004 zeroPad(sb, yearFromTime(t), 4);
jlaskey@3 1005 sb.append(' ');
hannesw@570 1006 zeroPad(sb, hourFromTime(t), 2);
jlaskey@3 1007 sb.append(':');
hannesw@570 1008 zeroPad(sb, minFromTime(t), 2);
jlaskey@3 1009 sb.append(':');
hannesw@570 1010 zeroPad(sb, secFromTime(t), 2);
jlaskey@3 1011 sb.append(" GMT");
jlaskey@3 1012 return sb.toString();
jlaskey@3 1013 }
jlaskey@3 1014
lagergren@112 1015 throw rangeError("invalid.date");
jlaskey@3 1016 }
jlaskey@3 1017
jlaskey@3 1018 private static String toISOStringImpl(final Object self) {
jlaskey@3 1019 final NativeDate nd = getNativeDate(self);
jlaskey@3 1020
jlaskey@3 1021 if (nd != null && nd.isValidDate()) {
jlaskey@3 1022 final StringBuilder sb = new StringBuilder(24);
jlaskey@3 1023 final double t = nd.getTime();
jlaskey@3 1024 // yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
hannesw@570 1025 zeroPad(sb, yearFromTime(t), 4);
jlaskey@3 1026 sb.append('-');
hannesw@570 1027 zeroPad(sb, monthFromTime(t) + 1, 2);
jlaskey@3 1028 sb.append('-');
hannesw@570 1029 zeroPad(sb, dayFromTime(t), 2);
jlaskey@3 1030 sb.append('T');
hannesw@570 1031 zeroPad(sb, hourFromTime(t), 2);
jlaskey@3 1032 sb.append(':');
hannesw@570 1033 zeroPad(sb, minFromTime(t), 2);
jlaskey@3 1034 sb.append(':');
hannesw@570 1035 zeroPad(sb, secFromTime(t), 2);
jlaskey@3 1036 sb.append('.');
hannesw@570 1037 zeroPad(sb, msFromTime(t), 3);
jlaskey@3 1038 sb.append("Z");
jlaskey@3 1039 return sb.toString();
jlaskey@3 1040 }
jlaskey@3 1041
lagergren@112 1042 throw rangeError("invalid.date");
jlaskey@3 1043 }
jlaskey@3 1044
jlaskey@3 1045 // ECMA 15.9.1.2 Day (t)
jlaskey@3 1046 private static double day(final double t) {
jlaskey@3 1047 return Math.floor(t / msPerDay);
jlaskey@3 1048 }
jlaskey@3 1049
jlaskey@3 1050 // ECMA 15.9.1.2 TimeWithinDay (t)
jlaskey@3 1051 private static double timeWithinDay(final double t) {
sundar@1072 1052 final double val = t % msPerDay;
sundar@1072 1053 return val < 0? val + msPerDay : val;
jlaskey@3 1054 }
jlaskey@3 1055
jlaskey@3 1056 // ECMA 15.9.1.3 InLeapYear (t)
jlaskey@3 1057 private static boolean isLeapYear(final int y) {
jlaskey@3 1058 return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
jlaskey@3 1059 }
jlaskey@3 1060
jlaskey@3 1061 // ECMA 15.9.1.3 DaysInYear (y)
jlaskey@3 1062 private static int daysInYear(final int y) {
jlaskey@3 1063 return isLeapYear(y) ? 366 : 365;
jlaskey@3 1064 }
jlaskey@3 1065
jlaskey@3 1066 // ECMA 15.9.1.3 DayFromYear (y)
jlaskey@3 1067 private static double dayFromYear(final double y) {
jlaskey@3 1068 return 365 * (y - 1970)
jlaskey@3 1069 + Math.floor((y -1969) / 4.0)
jlaskey@3 1070 - Math.floor((y - 1901) / 100.0)
jlaskey@3 1071 + Math.floor((y - 1601) / 400.0);
jlaskey@3 1072 }
jlaskey@3 1073
jlaskey@3 1074 // ECMA 15.9.1.3 Year Number
hannesw@570 1075 private static double timeFromYear(final int y) {
jlaskey@3 1076 return dayFromYear(y) * msPerDay;
jlaskey@3 1077 }
jlaskey@3 1078
hannesw@570 1079 // ECMA 15.9.1.3 Year Number
hannesw@570 1080 private static int yearFromTime(final double t) {
hannesw@570 1081 int y = (int) Math.floor(t / (msPerDay * 365.2425)) + 1970;
jlaskey@3 1082 final double t2 = timeFromYear(y);
jlaskey@3 1083 if (t2 > t) {
jlaskey@3 1084 y--;
hannesw@570 1085 } else if (t2 + msPerDay * daysInYear(y) <= t) {
jlaskey@3 1086 y++;
jlaskey@3 1087 }
jlaskey@3 1088 return y;
jlaskey@3 1089 }
jlaskey@3 1090
hannesw@570 1091 private static int dayWithinYear(final double t, final int year) {
hannesw@570 1092 return (int) (day(t) - dayFromYear(year));
jlaskey@3 1093 }
jlaskey@3 1094
hannesw@570 1095 private static int monthFromTime(final double t) {
hannesw@570 1096 final int year = yearFromTime(t);
hannesw@570 1097 final int day = dayWithinYear(t, year);
hannesw@570 1098 final int[] firstDay = firstDayInMonth[isLeapYear(year) ? 1 : 0];
jlaskey@3 1099 int month = 0;
jlaskey@3 1100
jlaskey@3 1101 while (month < 11 && firstDay[month + 1] <= day) {
jlaskey@3 1102 month++;
jlaskey@3 1103 }
jlaskey@3 1104 return month;
jlaskey@3 1105 }
jlaskey@3 1106
hannesw@570 1107 private static int dayFromTime(final double t) {
hannesw@570 1108 final int year = yearFromTime(t);
hannesw@570 1109 final int day = dayWithinYear(t, year);
hannesw@570 1110 final int[] firstDay = firstDayInMonth[isLeapYear(year) ? 1 : 0];
jlaskey@3 1111 int month = 0;
jlaskey@3 1112
jlaskey@3 1113 while (month < 11 && firstDay[month + 1] <= day) {
jlaskey@3 1114 month++;
jlaskey@3 1115 }
jlaskey@3 1116 return 1 + day - firstDay[month];
jlaskey@3 1117 }
jlaskey@3 1118
jlaskey@3 1119 private static int dayFromMonth(final int month, final int year) {
jlaskey@3 1120 assert(month >= 0 && month <= 11);
jlaskey@3 1121 final int[] firstDay = firstDayInMonth[isLeapYear(year) ? 1 : 0];
jlaskey@3 1122 return firstDay[month];
jlaskey@3 1123 }
jlaskey@3 1124
hannesw@570 1125 private static int weekDay(final double time) {
hannesw@570 1126 final int day = (int) (day(time) + 4) % 7;
jlaskey@3 1127 return day < 0 ? day + 7 : day;
jlaskey@3 1128 }
jlaskey@3 1129
jlaskey@3 1130 // ECMA 15.9.1.9 LocalTime
jlaskey@3 1131 private static double localTime(final double time, final TimeZone tz) {
jlaskey@3 1132 return time + tz.getOffset((long) time);
jlaskey@3 1133 }
jlaskey@3 1134
jlaskey@3 1135 // ECMA 15.9.1.9 UTC
jlaskey@3 1136 private static double utc(final double time, final TimeZone tz) {
jlaskey@3 1137 return time - tz.getOffset((long) (time - tz.getRawOffset()));
jlaskey@3 1138 }
jlaskey@3 1139
jlaskey@3 1140 // ECMA 15.9.1.10 Hours, Minutes, Second, and Milliseconds
hannesw@570 1141 private static int hourFromTime(final double t) {
hannesw@570 1142 final int h = (int) (Math.floor(t / msPerHour) % hoursPerDay);
jlaskey@3 1143 return h < 0 ? h + hoursPerDay: h;
jlaskey@3 1144 }
hannesw@570 1145 private static int minFromTime(final double t) {
hannesw@570 1146 final int m = (int) (Math.floor(t / msPerMinute) % minutesPerHour);
jlaskey@3 1147 return m < 0 ? m + minutesPerHour : m;
jlaskey@3 1148 }
jlaskey@3 1149
hannesw@570 1150 private static int secFromTime(final double t) {
hannesw@570 1151 final int s = (int) (Math.floor(t / msPerSecond) % secondsPerMinute);
jlaskey@3 1152 return s < 0 ? s + secondsPerMinute : s;
jlaskey@3 1153 }
jlaskey@3 1154
hannesw@570 1155 private static int msFromTime(final double t) {
hannesw@570 1156 final int m = (int) (t % msPerSecond);
jlaskey@3 1157 return m < 0 ? m + msPerSecond : m;
jlaskey@3 1158 }
jlaskey@3 1159
hannesw@570 1160 private static int valueFromTime(final int unit, final double t) {
jlaskey@3 1161 switch (unit) {
jlaskey@3 1162 case YEAR: return yearFromTime(t);
jlaskey@3 1163 case MONTH: return monthFromTime(t);
jlaskey@3 1164 case DAY: return dayFromTime(t);
jlaskey@3 1165 case HOUR: return hourFromTime(t);
jlaskey@3 1166 case MINUTE: return minFromTime(t);
jlaskey@3 1167 case SECOND: return secFromTime(t);
jlaskey@3 1168 case MILLISECOND: return msFromTime(t);
jlaskey@3 1169 default: throw new IllegalArgumentException(Integer.toString(unit));
jlaskey@3 1170 }
jlaskey@3 1171 }
jlaskey@3 1172
jlaskey@3 1173 // ECMA 15.9.1.11 MakeTime (hour, min, sec, ms)
jlaskey@3 1174 private static double makeTime(final double hour, final double min, final double sec, final double ms) {
jlaskey@3 1175 return hour * 3600000 + min * 60000 + sec * 1000 + ms;
jlaskey@3 1176 }
jlaskey@3 1177
jlaskey@3 1178 // ECMA 15.9.1.12 MakeDay (year, month, date)
jlaskey@3 1179 private static double makeDay(final double year, final double month, final double date) {
jlaskey@3 1180 final double y = year + Math.floor(month / 12);
hannesw@570 1181 int m = (int) (month % 12);
jlaskey@3 1182 if (m < 0) {
jlaskey@3 1183 m += 12;
jlaskey@3 1184 }
hannesw@570 1185 double d = dayFromYear(y);
hannesw@570 1186 d += dayFromMonth(m, (int) y);
jlaskey@3 1187
jlaskey@3 1188 return d + date - 1;
jlaskey@3 1189 }
jlaskey@3 1190
jlaskey@3 1191 // ECMA 15.9.1.13 MakeDate (day, time)
jlaskey@3 1192 private static double makeDate(final double day, final double time) {
jlaskey@3 1193 return day * msPerDay + time;
jlaskey@3 1194 }
jlaskey@3 1195
jlaskey@3 1196
jlaskey@3 1197 private static double makeDate(final Integer[] d) {
jlaskey@3 1198 final double time = makeDay(d[0], d[1], d[2]) * msPerDay;
jlaskey@3 1199 return time + makeTime(d[3], d[4], d[5], d[6]);
jlaskey@3 1200 }
jlaskey@3 1201
jlaskey@3 1202 private static double makeDate(final double[] d) {
jlaskey@3 1203 final double time = makeDay(d[0], d[1], d[2]) * msPerDay;
jlaskey@3 1204 return time + makeTime(d[3], d[4], d[5], d[6]);
jlaskey@3 1205 }
jlaskey@3 1206
jlaskey@3 1207 // Convert Date constructor args, checking for NaN, filling in defaults etc.
jlaskey@3 1208 private static double[] convertCtorArgs(final Object[] args) {
jlaskey@3 1209 final double[] d = new double[7];
sundar@169 1210 boolean nullReturn = false;
jlaskey@3 1211
sundar@169 1212 // should not bailout on first NaN or infinite. Need to convert all
sundar@169 1213 // subsequent args for possible side-effects via valueOf/toString overrides
sundar@169 1214 // on argument objects.
jlaskey@3 1215 for (int i = 0; i < d.length; i++) {
jlaskey@3 1216 if (i < args.length) {
jlaskey@3 1217 final double darg = JSType.toNumber(args[i]);
jlaskey@3 1218 if (isNaN(darg) || isInfinite(darg)) {
sundar@169 1219 nullReturn = true;
jlaskey@3 1220 }
sundar@169 1221
jlaskey@3 1222 d[i] = (long)darg;
jlaskey@3 1223 } else {
jlaskey@3 1224 d[i] = i == 2 ? 1 : 0; // day in month defaults to 1
jlaskey@3 1225 }
jlaskey@3 1226 }
jlaskey@3 1227
jlaskey@3 1228 if (0 <= d[0] && d[0] <= 99) {
jlaskey@3 1229 d[0] += 1900;
jlaskey@3 1230 }
jlaskey@3 1231
sundar@169 1232 return nullReturn? null : d;
jlaskey@3 1233 }
jlaskey@3 1234
jlaskey@3 1235 // This method does the hard work for all setter methods: If a value is provided
jlaskey@3 1236 // as argument it is used, otherwise the value is calculated from the existing time value.
jlaskey@3 1237 private static double[] convertArgs(final Object[] args, final double time, final int fieldId, final int start, final int length) {
jlaskey@3 1238 final double[] d = new double[length];
sundar@169 1239 boolean nullReturn = false;
jlaskey@3 1240
sundar@169 1241 // Need to call toNumber on all args for side-effects - even if an argument
sundar@169 1242 // fails to convert to number, subsequent toNumber calls needed for possible
sundar@169 1243 // side-effects via valueOf/toString overrides.
jlaskey@3 1244 for (int i = start; i < start + length; i++) {
jlaskey@3 1245 if (fieldId <= i && i < fieldId + args.length) {
jlaskey@3 1246 final double darg = JSType.toNumber(args[i - fieldId]);
jlaskey@3 1247 if (isNaN(darg) || isInfinite(darg)) {
sundar@169 1248 nullReturn = true;
jlaskey@3 1249 }
sundar@169 1250
jlaskey@3 1251 d[i - start] = (long) darg;
jlaskey@3 1252 } else {
jlaskey@3 1253 // Date.prototype.set* methods require first argument to be defined
jlaskey@3 1254 if (i == fieldId) {
sundar@169 1255 nullReturn = true;
jlaskey@3 1256 }
sundar@169 1257
hannesw@570 1258 if (!nullReturn && !isNaN(time)) {
sundar@169 1259 d[i - start] = valueFromTime(i, time);
sundar@169 1260 }
jlaskey@3 1261 }
jlaskey@3 1262 }
jlaskey@3 1263
hannesw@570 1264 return nullReturn ? null : d;
jlaskey@3 1265 }
jlaskey@3 1266
jlaskey@3 1267 // ECMA 15.9.1.14 TimeClip (time)
jlaskey@3 1268 private static double timeClip(final double time) {
jlaskey@3 1269 if (isInfinite(time) || isNaN(time) || Math.abs(time) > 8.64e15) {
jlaskey@3 1270 return Double.NaN;
jlaskey@3 1271 }
jlaskey@3 1272 return (long)time;
jlaskey@3 1273 }
jlaskey@3 1274
jlaskey@3 1275 private static NativeDate ensureNativeDate(final Object self) {
jlaskey@3 1276 return getNativeDate(self);
jlaskey@3 1277 }
jlaskey@3 1278
jlaskey@3 1279 private static NativeDate getNativeDate(final Object self) {
jlaskey@3 1280 if (self instanceof NativeDate) {
jlaskey@3 1281 return (NativeDate)self;
jlaskey@3 1282 } else if (self != null && self == Global.instance().getDatePrototype()) {
sundar@1267 1283 return Global.instance().getDefaultDate();
jlaskey@3 1284 } else {
lagergren@112 1285 throw typeError("not.a.date", ScriptRuntime.safeToString(self));
jlaskey@3 1286 }
jlaskey@3 1287 }
jlaskey@3 1288
sundar@774 1289 private static double getField(final Object self, final int field) {
jlaskey@3 1290 final NativeDate nd = getNativeDate(self);
sundar@774 1291 return (nd != null && nd.isValidDate()) ? (double)valueFromTime(field, nd.getLocalTime()) : Double.NaN;
jlaskey@3 1292 }
jlaskey@3 1293
sundar@774 1294 private static double getUTCField(final Object self, final int field) {
jlaskey@3 1295 final NativeDate nd = getNativeDate(self);
sundar@774 1296 return (nd != null && nd.isValidDate()) ? (double)valueFromTime(field, nd.getTime()) : Double.NaN;
jlaskey@3 1297 }
jlaskey@3 1298
jlaskey@3 1299 private static void setFields(final NativeDate nd, final int fieldId, final Object[] args, final boolean local) {
jlaskey@3 1300 int start, length;
jlaskey@3 1301 if (fieldId < HOUR) {
jlaskey@3 1302 start = YEAR;
jlaskey@3 1303 length = 3;
jlaskey@3 1304 } else {
jlaskey@3 1305 start = HOUR;
jlaskey@3 1306 length = 4;
jlaskey@3 1307 }
jlaskey@3 1308 final double time = local ? nd.getLocalTime() : nd.getTime();
jlaskey@3 1309 final double d[] = convertArgs(args, time, fieldId, start, length);
jlaskey@3 1310
sundar@229 1311 if (! nd.isValidDate()) {
sundar@229 1312 return;
sundar@229 1313 }
sundar@229 1314
jlaskey@3 1315 double newTime;
jlaskey@3 1316 if (d == null) {
jlaskey@3 1317 newTime = NaN;
jlaskey@3 1318 } else {
jlaskey@3 1319 if (start == YEAR) {
jlaskey@3 1320 newTime = makeDate(makeDay(d[0], d[1], d[2]), timeWithinDay(time));
jlaskey@3 1321 } else {
jlaskey@3 1322 newTime = makeDate(day(time), makeTime(d[0], d[1], d[2], d[3]));
jlaskey@3 1323 }
jlaskey@3 1324 if (local) {
jlaskey@3 1325 newTime = utc(newTime, nd.getTimeZone());
jlaskey@3 1326 }
jlaskey@3 1327 newTime = timeClip(newTime);
jlaskey@3 1328 }
jlaskey@3 1329 nd.setTime(newTime);
jlaskey@3 1330 }
jlaskey@3 1331
jlaskey@3 1332 private boolean isValidDate() {
jlaskey@3 1333 return !isNaN(time);
jlaskey@3 1334 }
jlaskey@3 1335
jlaskey@3 1336 private double getLocalTime() {
jlaskey@3 1337 return localTime(time, timezone);
jlaskey@3 1338 }
jlaskey@3 1339
jlaskey@3 1340 private double getTime() {
jlaskey@3 1341 return time;
jlaskey@3 1342 }
jlaskey@3 1343
jlaskey@3 1344 private void setTime(final double time) {
jlaskey@3 1345 this.time = time;
jlaskey@3 1346 }
jlaskey@3 1347
jlaskey@3 1348 private TimeZone getTimeZone() {
jlaskey@3 1349 return timezone;
jlaskey@3 1350 }
jlaskey@3 1351 }

mercurial