NativeDate.java revision 1077:dd7bbdf81a53
1215911Sjfv/* 2215911Sjfv * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3235528Sjfv * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4215911Sjfv * 5215911Sjfv * This code is free software; you can redistribute it and/or modify it 6215911Sjfv * under the terms of the GNU General Public License version 2 only, as 7215911Sjfv * published by the Free Software Foundation. Oracle designates this 8215911Sjfv * particular file as subject to the "Classpath" exception as provided 9215911Sjfv * by Oracle in the LICENSE file that accompanied this code. 10215911Sjfv * 11215911Sjfv * This code is distributed in the hope that it will be useful, but WITHOUT 12215911Sjfv * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13215911Sjfv * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14215911Sjfv * version 2 for more details (a copy is included in the LICENSE file that 15215911Sjfv * accompanied this code). 16215911Sjfv * 17215911Sjfv * You should have received a copy of the GNU General Public License version 18215911Sjfv * 2 along with this work; if not, write to the Free Software Foundation, 19215911Sjfv * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20215911Sjfv * 21215911Sjfv * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22215911Sjfv * or visit www.oracle.com if you need additional information or have any 23215911Sjfv * questions. 24215911Sjfv */ 25215911Sjfv 26215911Sjfvpackage jdk.nashorn.internal.objects; 27215911Sjfv 28215911Sjfvimport static java.lang.Double.NaN; 29215911Sjfvimport static java.lang.Double.isInfinite; 30215911Sjfvimport static java.lang.Double.isNaN; 31215911Sjfvimport static jdk.nashorn.internal.runtime.ECMAErrors.rangeError; 32215911Sjfvimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 33215911Sjfvimport java.util.Locale; 34215911Sjfvimport java.util.TimeZone; 35215911Sjfvimport java.util.concurrent.Callable; 36222588Sjfvimport jdk.nashorn.internal.objects.annotations.Attribute; 37222588Sjfvimport jdk.nashorn.internal.objects.annotations.Constructor; 38215911Sjfvimport jdk.nashorn.internal.objects.annotations.Function; 39215911Sjfvimport jdk.nashorn.internal.objects.annotations.ScriptClass; 40215911Sjfvimport jdk.nashorn.internal.objects.annotations.SpecializedFunction; 41215911Sjfvimport jdk.nashorn.internal.objects.annotations.Where; 42215911Sjfvimport jdk.nashorn.internal.parser.DateParser; 43215911Sjfvimport jdk.nashorn.internal.runtime.ConsString; 44215911Sjfvimport jdk.nashorn.internal.runtime.JSType; 45238263Sjfvimport jdk.nashorn.internal.runtime.PropertyMap; 46215911Sjfvimport jdk.nashorn.internal.runtime.ScriptEnvironment; 47215911Sjfvimport jdk.nashorn.internal.runtime.ScriptObject; 48215911Sjfvimport jdk.nashorn.internal.runtime.ScriptRuntime; 49215911Sjfvimport jdk.nashorn.internal.runtime.linker.Bootstrap; 50215911Sjfvimport jdk.nashorn.internal.runtime.linker.InvokeByName; 51215911Sjfv 52215911Sjfv/** 53215911Sjfv * ECMA 15.9 Date Objects 54215911Sjfv * 55215911Sjfv */ 56215911Sjfv@ScriptClass("Date") 57215911Sjfvpublic final class NativeDate extends ScriptObject { 58215911Sjfv 59215911Sjfv private static final String INVALID_DATE = "Invalid Date"; 60235528Sjfv 61215911Sjfv private static final int YEAR = 0; 62215911Sjfv private static final int MONTH = 1; 63215911Sjfv private static final int DAY = 2; 64215911Sjfv private static final int HOUR = 3; 65215911Sjfv private static final int MINUTE = 4; 66215911Sjfv private static final int SECOND = 5; 67215911Sjfv private static final int MILLISECOND = 6; 68215911Sjfv 69215911Sjfv private static final int FORMAT_DATE_TIME = 0; 70215911Sjfv private static final int FORMAT_DATE = 1; 71215911Sjfv private static final int FORMAT_TIME = 2; 72215911Sjfv private static final int FORMAT_LOCAL_DATE_TIME = 3; 73215911Sjfv private static final int FORMAT_LOCAL_DATE = 4; 74215911Sjfv private static final int FORMAT_LOCAL_TIME = 5; 75215911Sjfv 76215911Sjfv // Constants defined in ECMA 15.9.1.10 77215911Sjfv private static final int hoursPerDay = 24; 78215911Sjfv private static final int minutesPerHour = 60; 79215911Sjfv private static final int secondsPerMinute = 60; 80215911Sjfv private static final int msPerSecond = 1_000; 81215911Sjfv private static final int msPerMinute = 60_000; 82215911Sjfv private static final double msPerHour = 3_600_000; 83215911Sjfv private static final double msPerDay = 86_400_000; 84215911Sjfv 85215911Sjfv private static int[][] firstDayInMonth = { 86215911Sjfv {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, // normal year 87215911Sjfv {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} // leap year 88215911Sjfv }; 89215911Sjfv 90215911Sjfv private static String[] weekDays = { 91215911Sjfv "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 92215911Sjfv }; 93215911Sjfv 94215911Sjfv private static String[] months = { 95215911Sjfv "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 96215911Sjfv }; 97215911Sjfv 98215911Sjfv private static final Object TO_ISO_STRING = new Object(); 99215911Sjfv 100215911Sjfv private static InvokeByName getTO_ISO_STRING() { 101215911Sjfv return Global.instance().getInvokeByName(TO_ISO_STRING, 102215911Sjfv new Callable<InvokeByName>() { 103215911Sjfv @Override 104215911Sjfv public InvokeByName call() { 105215911Sjfv return new InvokeByName("toISOString", ScriptObject.class, Object.class, Object.class); 106215911Sjfv } 107215911Sjfv }); 108215911Sjfv } 109215911Sjfv 110215911Sjfv private double time; 111215911Sjfv private final TimeZone timezone; 112215911Sjfv 113215911Sjfv // initialized by nasgen 114215911Sjfv private static PropertyMap $nasgenmap$; 115215911Sjfv 116215911Sjfv private NativeDate(final double time, final ScriptObject proto, final PropertyMap map) { 117215911Sjfv super(proto, map); 118215911Sjfv final ScriptEnvironment env = Global.getEnv(); 119215911Sjfv 120215911Sjfv this.time = time; 121215911Sjfv this.timezone = env._timezone; 122215911Sjfv } 123215911Sjfv 124215911Sjfv NativeDate(final double time, final Global global) { 125215911Sjfv this(time, global.getDatePrototype(), $nasgenmap$); 126215911Sjfv } 127215911Sjfv 128215911Sjfv private NativeDate (final double time) { 129215911Sjfv this(time, Global.instance()); 130215911Sjfv } 131215911Sjfv 132215911Sjfv private NativeDate() { 133215911Sjfv this(System.currentTimeMillis()); 134215911Sjfv } 135215911Sjfv 136215911Sjfv @Override 137215911Sjfv public String getClassName() { 138215911Sjfv return "Date"; 139215911Sjfv } 140215911Sjfv 141215911Sjfv // ECMA 8.12.8 [[DefaultValue]] (hint) 142215911Sjfv @Override 143215911Sjfv public Object getDefaultValue(final Class<?> hint) { 144215911Sjfv // When the [[DefaultValue]] internal method of O is called with no hint, 145215911Sjfv // then it behaves as if the hint were Number, unless O is a Date object 146215911Sjfv // in which case it behaves as if the hint were String. 147215911Sjfv return super.getDefaultValue(hint == null ? String.class : hint); 148215911Sjfv } 149215911Sjfv 150215911Sjfv /** 151215911Sjfv * Constructor - ECMA 15.9.3.1 new Date 152215911Sjfv * 153215911Sjfv * @param isNew is this Date constructed with the new operator 154215911Sjfv * @param self self references 155215911Sjfv * @return Date representing now 156215911Sjfv */ 157215911Sjfv @SpecializedFunction(isConstructor=true) 158215911Sjfv public static Object construct(final boolean isNew, final Object self) { 159215911Sjfv final NativeDate result = new NativeDate(); 160215911Sjfv return isNew ? result : toStringImpl(result, FORMAT_DATE_TIME); 161215911Sjfv } 162215911Sjfv 163215911Sjfv /** 164215911Sjfv * Constructor - ECMA 15.9.3.1 new Date (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] ) 165215911Sjfv * 166215911Sjfv * @param isNew is this Date constructed with the new operator 167215911Sjfv * @param self self reference 168215911Sjfv * @param args arguments 169215911Sjfv * @return new Date 170215911Sjfv */ 171215911Sjfv @Constructor(arity = 7) 172215911Sjfv public static Object construct(final boolean isNew, final Object self, final Object... args) { 173215911Sjfv if (! isNew) { 174215911Sjfv return toStringImpl(new NativeDate(), FORMAT_DATE_TIME); 175215911Sjfv } 176215911Sjfv 177215911Sjfv NativeDate result; 178215911Sjfv switch (args.length) { 179215911Sjfv case 0: 180215911Sjfv result = new NativeDate(); 181215911Sjfv break; 182215911Sjfv 183215911Sjfv case 1: 184215911Sjfv double num; 185215911Sjfv final Object arg = JSType.toPrimitive(args[0]); 186215911Sjfv if (arg instanceof String || arg instanceof ConsString) { 187215911Sjfv num = parseDateString(arg.toString()); 188215911Sjfv } else { 189215911Sjfv num = timeClip(JSType.toNumber(args[0])); 190215911Sjfv } 191215911Sjfv result = new NativeDate(num); 192215911Sjfv break; 193215911Sjfv 194215911Sjfv default: 195215911Sjfv result = new NativeDate(0); 196215911Sjfv final double[] d = convertCtorArgs(args); 197215911Sjfv if (d == null) { 198215911Sjfv result.setTime(Double.NaN); 199215911Sjfv } else { 200215911Sjfv final double time = timeClip(utc(makeDate(d), result.getTimeZone())); 201215911Sjfv result.setTime(time); 202215911Sjfv } 203215911Sjfv break; 204215911Sjfv } 205215911Sjfv 206215911Sjfv return result; 207215911Sjfv } 208215911Sjfv 209215911Sjfv @Override 210215911Sjfv public String safeToString() { 211229153Smdf final String str = isValidDate() ? toISOStringImpl(this) : INVALID_DATE; 212215911Sjfv return "[Date " + str + "]"; 213215911Sjfv } 214215911Sjfv 215215911Sjfv @Override 216215911Sjfv public String toString() { 217215911Sjfv return isValidDate() ? toString(this).toString() : INVALID_DATE; 218215911Sjfv } 219215911Sjfv 220215911Sjfv /** 221215911Sjfv * ECMA 15.9.4.2 Date.parse (string) 222215911Sjfv * 223215911Sjfv * @param self self reference 224215911Sjfv * @param string string to parse as date 225215911Sjfv * @return Date interpreted from the string, or NaN for illegal values 226215911Sjfv */ 227215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 228215911Sjfv public static double parse(final Object self, final Object string) { 229215911Sjfv return parseDateString(JSType.toString(string)); 230215911Sjfv } 231215911Sjfv 232215911Sjfv /** 233215911Sjfv * ECMA 15.9.4.3 Date.UTC (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] ) 234215911Sjfv * 235215911Sjfv * @param self self reference 236215911Sjfv * @param args mandatory args are year, month. Optional are date, hours, minutes, seconds and milliseconds 237215911Sjfv * @return a time clip according to the ECMA specification 238215911Sjfv */ 239222588Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 7, where = Where.CONSTRUCTOR) 240215911Sjfv public static double UTC(final Object self, final Object... args) { 241215911Sjfv final NativeDate nd = new NativeDate(0); 242215911Sjfv final double[] d = convertCtorArgs(args); 243215911Sjfv final double time = d == null ? Double.NaN : timeClip(makeDate(d)); 244215911Sjfv nd.setTime(time); 245215911Sjfv return time; 246215911Sjfv } 247215911Sjfv 248215911Sjfv /** 249215911Sjfv * ECMA 15.9.4.4 Date.now ( ) 250215911Sjfv * 251215911Sjfv * @param self self reference 252215911Sjfv * @return a Date that points to the current moment in time 253215911Sjfv */ 254215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 255215911Sjfv public static long now(final Object self) { 256215911Sjfv return System.currentTimeMillis(); 257215911Sjfv } 258215911Sjfv 259215911Sjfv /** 260215911Sjfv * ECMA 15.9.5.2 Date.prototype.toString ( ) 261215911Sjfv * 262215911Sjfv * @param self self reference 263215911Sjfv * @return string value that represents the Date in the current time zone 264215911Sjfv */ 265215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 266215911Sjfv public static String toString(final Object self) { 267215911Sjfv return toStringImpl(self, FORMAT_DATE_TIME); 268215911Sjfv } 269215911Sjfv 270215911Sjfv /** 271215911Sjfv * ECMA 15.9.5.3 Date.prototype.toDateString ( ) 272215911Sjfv * 273215911Sjfv * @param self self reference 274215911Sjfv * @return string value with the "date" part of the Date in the current time zone 275215911Sjfv */ 276222588Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 277215911Sjfv public static String toDateString(final Object self) { 278215911Sjfv return toStringImpl(self, FORMAT_DATE); 279215911Sjfv } 280215911Sjfv 281215911Sjfv /** 282215911Sjfv * ECMA 15.9.5.4 Date.prototype.toTimeString ( ) 283215911Sjfv * 284215911Sjfv * @param self self reference 285215911Sjfv * @return string value with "time" part of Date in the current time zone 286215911Sjfv */ 287215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 288215911Sjfv public static String toTimeString(final Object self) { 289215911Sjfv return toStringImpl(self, FORMAT_TIME); 290215911Sjfv } 291215911Sjfv 292215911Sjfv /** 293215911Sjfv * ECMA 15.9.5.5 Date.prototype.toLocaleString ( ) 294215911Sjfv * 295215911Sjfv * @param self self reference 296215911Sjfv * @return string value that represents the Data in the current time zone and locale 297215911Sjfv */ 298215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 299215911Sjfv public static String toLocaleString(final Object self) { 300215911Sjfv return toStringImpl(self, FORMAT_LOCAL_DATE_TIME); 301215911Sjfv } 302215911Sjfv 303215911Sjfv /** 304215911Sjfv * ECMA 15.9.5.6 Date.prototype.toLocaleDateString ( ) 305215911Sjfv * 306215911Sjfv * @param self self reference 307215911Sjfv * @return string value with the "date" part of the Date in the current time zone and locale 308215911Sjfv */ 309215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 310215911Sjfv public static String toLocaleDateString(final Object self) { 311215911Sjfv return toStringImpl(self, FORMAT_LOCAL_DATE); 312215911Sjfv } 313215911Sjfv 314215911Sjfv /** 315215911Sjfv * ECMA 15.9.5.7 Date.prototype.toLocaleTimeString ( ) 316215911Sjfv * 317215911Sjfv * @param self self reference 318215911Sjfv * @return string value with the "time" part of Date in the current time zone and locale 319215911Sjfv */ 320215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 321215911Sjfv public static String toLocaleTimeString(final Object self) { 322215911Sjfv return toStringImpl(self, FORMAT_LOCAL_TIME); 323215911Sjfv } 324215911Sjfv 325215911Sjfv /** 326215911Sjfv * ECMA 15.9.5.8 Date.prototype.valueOf ( ) 327215911Sjfv * 328215911Sjfv * @param self self reference 329215911Sjfv * @return valueOf - a number which is this time value 330215911Sjfv */ 331215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 332215911Sjfv public static double valueOf(final Object self) { 333215911Sjfv final NativeDate nd = getNativeDate(self); 334215911Sjfv return (nd != null) ? nd.getTime() : Double.NaN; 335215911Sjfv } 336215911Sjfv 337215911Sjfv /** 338215911Sjfv * ECMA 15.9.5.9 Date.prototype.getTime ( ) 339215911Sjfv * 340215911Sjfv * @param self self reference 341215911Sjfv * @return time 342215911Sjfv */ 343215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 344215911Sjfv public static double getTime(final Object self) { 345215911Sjfv final NativeDate nd = getNativeDate(self); 346215911Sjfv return (nd != null) ? nd.getTime() : Double.NaN; 347215911Sjfv } 348215911Sjfv 349215911Sjfv /** 350215911Sjfv * ECMA 15.9.5.10 Date.prototype.getFullYear ( ) 351215911Sjfv * 352215911Sjfv * @param self self reference 353215911Sjfv * @return full year 354215911Sjfv */ 355215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 356215911Sjfv public static Object getFullYear(final Object self) { 357215911Sjfv return getField(self, YEAR); 358215911Sjfv } 359215911Sjfv 360215911Sjfv /** 361215911Sjfv * ECMA 15.9.5.11 Date.prototype.getUTCFullYear( ) 362215911Sjfv * 363215911Sjfv * @param self self reference 364215911Sjfv * @return UTC full year 365215911Sjfv */ 366215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 367215911Sjfv public static double getUTCFullYear(final Object self) { 368215911Sjfv return getUTCField(self, YEAR); 369215911Sjfv } 370215911Sjfv 371215911Sjfv /** 372215911Sjfv * B.2.4 Date.prototype.getYear ( ) 373215911Sjfv * 374215911Sjfv * @param self self reference 375215911Sjfv * @return year 376215911Sjfv */ 377215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 378215911Sjfv public static double getYear(final Object self) { 379215911Sjfv final NativeDate nd = getNativeDate(self); 380215911Sjfv return (nd != null && nd.isValidDate()) ? (yearFromTime(nd.getLocalTime()) - 1900) : Double.NaN; 381215911Sjfv } 382215911Sjfv 383215911Sjfv /** 384238263Sjfv * ECMA 15.9.5.12 Date.prototype.getMonth ( ) 385235528Sjfv * 386215911Sjfv * @param self self reference 387215911Sjfv * @return month 388215911Sjfv */ 389215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 390215911Sjfv public static double getMonth(final Object self) { 391215911Sjfv return getField(self, MONTH); 392215911Sjfv } 393215911Sjfv 394215911Sjfv /** 395215911Sjfv * ECMA 15.9.5.13 Date.prototype.getUTCMonth ( ) 396215911Sjfv * 397215911Sjfv * @param self self reference 398215911Sjfv * @return UTC month 399215911Sjfv */ 400215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 401215911Sjfv public static double getUTCMonth(final Object self) { 402215911Sjfv return getUTCField(self, MONTH); 403215911Sjfv } 404215911Sjfv 405215911Sjfv /** 406215911Sjfv * ECMA 15.9.5.14 Date.prototype.getDate ( ) 407215911Sjfv * 408215911Sjfv * @param self self reference 409215911Sjfv * @return date 410215911Sjfv */ 411215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 412215911Sjfv public static double getDate(final Object self) { 413215911Sjfv return getField(self, DAY); 414215911Sjfv } 415215911Sjfv 416215911Sjfv /** 417215911Sjfv * ECMA 15.9.5.15 Date.prototype.getUTCDate ( ) 418215911Sjfv * 419215911Sjfv * @param self self reference 420215911Sjfv * @return UTC Date 421215911Sjfv */ 422215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 423215911Sjfv public static double getUTCDate(final Object self) { 424215911Sjfv return getUTCField(self, DAY); 425215911Sjfv } 426215911Sjfv 427215911Sjfv /** 428215911Sjfv * ECMA 15.9.5.16 Date.prototype.getDay ( ) 429215911Sjfv * 430215911Sjfv * @param self self reference 431215911Sjfv * @return day 432215911Sjfv */ 433215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 434215911Sjfv public static double getDay(final Object self) { 435215911Sjfv final NativeDate nd = getNativeDate(self); 436215911Sjfv return (nd != null && nd.isValidDate()) ? weekDay(nd.getLocalTime()) : Double.NaN; 437215911Sjfv } 438215911Sjfv 439215911Sjfv /** 440215911Sjfv * ECMA 15.9.5.17 Date.prototype.getUTCDay ( ) 441215911Sjfv * 442215911Sjfv * @param self self reference 443215911Sjfv * @return UTC day 444215911Sjfv */ 445215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 446215911Sjfv public static double getUTCDay(final Object self) { 447215911Sjfv final NativeDate nd = getNativeDate(self); 448215911Sjfv return (nd != null && nd.isValidDate()) ? weekDay(nd.getTime()) : Double.NaN; 449215911Sjfv } 450215911Sjfv 451215911Sjfv /** 452215911Sjfv * ECMA 15.9.5.18 Date.prototype.getHours ( ) 453215911Sjfv * 454215911Sjfv * @param self self reference 455215911Sjfv * @return hours 456215911Sjfv */ 457215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 458215911Sjfv public static double getHours(final Object self) { 459215911Sjfv return getField(self, HOUR); 460215911Sjfv } 461215911Sjfv 462215911Sjfv /** 463215911Sjfv * ECMA 15.9.5.19 Date.prototype.getUTCHours ( ) 464215911Sjfv * 465215911Sjfv * @param self self reference 466215911Sjfv * @return UTC hours 467215911Sjfv */ 468215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 469215911Sjfv public static double getUTCHours(final Object self) { 470215911Sjfv return getUTCField(self, HOUR); 471215911Sjfv } 472215911Sjfv 473215911Sjfv /** 474215911Sjfv * ECMA 15.9.5.20 Date.prototype.getMinutes ( ) 475215911Sjfv * 476215911Sjfv * @param self self reference 477215911Sjfv * @return minutes 478215911Sjfv */ 479215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 480215911Sjfv public static double getMinutes(final Object self) { 481215911Sjfv return getField(self, MINUTE); 482215911Sjfv } 483215911Sjfv 484215911Sjfv /** 485215911Sjfv * ECMA 15.9.5.21 Date.prototype.getUTCMinutes ( ) 486215911Sjfv * 487215911Sjfv * @param self self reference 488215911Sjfv * @return UTC minutes 489215911Sjfv */ 490215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 491215911Sjfv public static double getUTCMinutes(final Object self) { 492215911Sjfv return getUTCField(self, MINUTE); 493215911Sjfv } 494215911Sjfv 495215911Sjfv /** 496215911Sjfv * ECMA 15.9.5.22 Date.prototype.getSeconds ( ) 497215911Sjfv * 498215911Sjfv * @param self self reference 499215911Sjfv * @return seconds 500215911Sjfv */ 501215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 502215911Sjfv public static double getSeconds(final Object self) { 503215911Sjfv return getField(self, SECOND); 504215911Sjfv } 505215911Sjfv 506215911Sjfv /** 507215911Sjfv * ECMA 15.9.5.23 Date.prototype.getUTCSeconds ( ) 508215911Sjfv * 509215911Sjfv * @param self self reference 510215911Sjfv * @return UTC seconds 511215911Sjfv */ 512215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 513215911Sjfv public static double getUTCSeconds(final Object self) { 514215911Sjfv return getUTCField(self, SECOND); 515215911Sjfv } 516215911Sjfv 517215911Sjfv /** 518215911Sjfv * ECMA 15.9.5.24 Date.prototype.getMilliseconds ( ) 519215911Sjfv * 520215911Sjfv * @param self self reference 521215911Sjfv * @return milliseconds 522215911Sjfv */ 523215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 524215911Sjfv public static double getMilliseconds(final Object self) { 525215911Sjfv return getField(self, MILLISECOND); 526215911Sjfv } 527215911Sjfv 528215911Sjfv /** 529215911Sjfv * ECMA 15.9.5.25 Date.prototype.getUTCMilliseconds ( ) 530215911Sjfv * 531215911Sjfv * @param self self reference 532215911Sjfv * @return UTC milliseconds 533215911Sjfv */ 534215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 535215911Sjfv public static double getUTCMilliseconds(final Object self) { 536215911Sjfv return getUTCField(self, MILLISECOND); 537215911Sjfv } 538215911Sjfv 539215911Sjfv /** 540215911Sjfv * ECMA 15.9.5.26 Date.prototype.getTimezoneOffset ( ) 541215911Sjfv * 542215911Sjfv * @param self self reference 543215911Sjfv * @return time zone offset or NaN if N/A 544215911Sjfv */ 545215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 546215911Sjfv public static double getTimezoneOffset(final Object self) { 547215911Sjfv final NativeDate nd = getNativeDate(self); 548215911Sjfv if (nd != null && nd.isValidDate()) { 549215911Sjfv final long msec = (long) nd.getTime(); 550215911Sjfv return - nd.getTimeZone().getOffset(msec) / msPerMinute; 551215911Sjfv } 552215911Sjfv return Double.NaN; 553215911Sjfv } 554215911Sjfv 555215911Sjfv /** 556215911Sjfv * ECMA 15.9.5.27 Date.prototype.setTime (time) 557215911Sjfv * 558215911Sjfv * @param self self reference 559215911Sjfv * @param time time 560215911Sjfv * @return time 561215911Sjfv */ 562215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 563215911Sjfv public static double setTime(final Object self, final Object time) { 564215911Sjfv final NativeDate nd = getNativeDate(self); 565215911Sjfv final double num = timeClip(JSType.toNumber(time)); 566215911Sjfv nd.setTime(num); 567215911Sjfv return num; 568215911Sjfv } 569215911Sjfv 570215911Sjfv /** 571215911Sjfv * ECMA 15.9.5.28 Date.prototype.setMilliseconds (ms) 572215911Sjfv * 573215911Sjfv * @param self self reference 574215911Sjfv * @param args milliseconds 575215911Sjfv * @return time 576215911Sjfv */ 577215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 578215911Sjfv public static double setMilliseconds(final Object self, final Object... args) { 579215911Sjfv final NativeDate nd = getNativeDate(self); 580215911Sjfv setFields(nd, MILLISECOND, args, true); 581215911Sjfv return nd.getTime(); 582215911Sjfv } 583215911Sjfv 584215911Sjfv /** 585215911Sjfv * ECMA 15.9.5.29 Date.prototype.setUTCMilliseconds (ms) 586215911Sjfv * 587215911Sjfv * @param self self reference 588215911Sjfv * @param args utc milliseconds 589215911Sjfv * @return time 590215911Sjfv */ 591215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 592215911Sjfv public static double setUTCMilliseconds(final Object self, final Object... args) { 593215911Sjfv final NativeDate nd = getNativeDate(self); 594215911Sjfv setFields(nd, MILLISECOND, args, false); 595215911Sjfv return nd.getTime(); 596215911Sjfv } 597215911Sjfv 598215911Sjfv /** 599215911Sjfv * ECMA 15.9.5.30 Date.prototype.setSeconds (sec [, ms ] ) 600215911Sjfv * 601215911Sjfv * @param self self reference 602215911Sjfv * @param args seconds (milliseconds optional second argument) 603215911Sjfv * @return time 604215911Sjfv */ 605215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 606215911Sjfv public static double setSeconds(final Object self, final Object... args) { 607215911Sjfv final NativeDate nd = getNativeDate(self); 608215911Sjfv setFields(nd, SECOND, args, true); 609215911Sjfv return nd.getTime(); 610215911Sjfv } 611215911Sjfv 612215911Sjfv /** 613215911Sjfv * ECMA 15.9.5.31 Date.prototype.setUTCSeconds (sec [, ms ] ) 614215911Sjfv * 615215911Sjfv * @param self self reference 616215911Sjfv * @param args UTC seconds (milliseconds optional second argument) 617215911Sjfv * @return time 618215911Sjfv */ 619215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 620215911Sjfv public static double setUTCSeconds(final Object self, final Object... args) { 621215911Sjfv final NativeDate nd = getNativeDate(self); 622215911Sjfv setFields(nd, SECOND, args, false); 623215911Sjfv return nd.getTime(); 624215911Sjfv } 625215911Sjfv 626215911Sjfv /** 627215911Sjfv * ECMA 15.9.5.32 Date.prototype.setMinutes (min [, sec [, ms ] ] ) 628215911Sjfv * 629215911Sjfv * @param self self reference 630215911Sjfv * @param args minutes (seconds and milliseconds are optional second and third arguments) 631215911Sjfv * @return time 632215911Sjfv */ 633215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) 634215911Sjfv public static double setMinutes(final Object self, final Object... args) { 635215911Sjfv final NativeDate nd = getNativeDate(self); 636215911Sjfv setFields(nd, MINUTE, args, true); 637215911Sjfv return nd.getTime(); 638215911Sjfv } 639243440Sglebius 640243440Sglebius /** 641243440Sglebius * ECMA 15.9.5.33 Date.prototype.setUTCMinutes (min [, sec [, ms ] ] ) 642215911Sjfv * 643215911Sjfv * @param self self reference 644215911Sjfv * @param args minutes (seconds and milliseconds are optional second and third arguments) 645215911Sjfv * @return time 646215911Sjfv */ 647215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) 648215911Sjfv public static double setUTCMinutes(final Object self, final Object... args) { 649215911Sjfv final NativeDate nd = getNativeDate(self); 650215911Sjfv setFields(nd, MINUTE, args, false); 651215911Sjfv return nd.getTime(); 652215911Sjfv } 653215911Sjfv 654215911Sjfv /** 655215911Sjfv * ECMA 15.9.5.34 Date.prototype.setHours (hour [, min [, sec [, ms ] ] ] ) 656215911Sjfv * 657215911Sjfv * @param self self reference 658215911Sjfv * @param args hour (optional arguments after are minutes, seconds, milliseconds) 659215911Sjfv * @return time 660215911Sjfv */ 661215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4) 662215911Sjfv public static double setHours(final Object self, final Object... args) { 663215911Sjfv final NativeDate nd = getNativeDate(self); 664215911Sjfv setFields(nd, HOUR, args, true); 665215911Sjfv return nd.getTime(); 666215911Sjfv } 667215911Sjfv 668215911Sjfv /** 669215911Sjfv * ECMA 15.9.5.35 Date.prototype.setUTCHours (hour [, min [, sec [, ms ] ] ] ) 670215911Sjfv * 671215911Sjfv * @param self self reference 672215911Sjfv * @param args hour (optional arguments after are minutes, seconds, milliseconds) 673215911Sjfv * @return time 674215911Sjfv */ 675215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4) 676215911Sjfv public static double setUTCHours(final Object self, final Object... args) { 677215911Sjfv final NativeDate nd = getNativeDate(self); 678215911Sjfv setFields(nd, HOUR, args, false); 679215911Sjfv return nd.getTime(); 680215911Sjfv } 681215911Sjfv 682215911Sjfv /** 683215911Sjfv * ECMA 15.9.5.36 Date.prototype.setDate (date) 684215911Sjfv * 685215911Sjfv * @param self self reference 686215911Sjfv * @param args date 687215911Sjfv * @return time 688215911Sjfv */ 689215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 690215911Sjfv public static double setDate(final Object self, final Object... args) { 691215911Sjfv final NativeDate nd = getNativeDate(self); 692215911Sjfv setFields(nd, DAY, args, true); 693215911Sjfv return nd.getTime(); 694215911Sjfv } 695215911Sjfv 696215911Sjfv /** 697222588Sjfv * ECMA 15.9.5.37 Date.prototype.setUTCDate (date) 698222592Sjfv * 699222588Sjfv * @param self self reference 700222588Sjfv * @param args UTC date 701215911Sjfv * @return time 702215911Sjfv */ 703215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 704215911Sjfv public static double setUTCDate(final Object self, final Object... args) { 705222588Sjfv final NativeDate nd = getNativeDate(self); 706222588Sjfv setFields(nd, DAY, args, false); 707222588Sjfv return nd.getTime(); 708222588Sjfv } 709222588Sjfv 710222588Sjfv /** 711222588Sjfv * ECMA 15.9.5.38 Date.prototype.setMonth (month [, date ] ) 712222588Sjfv * 713222588Sjfv * @param self self reference 714222588Sjfv * @param args month (optional second argument is date) 715222588Sjfv * @return time 716222588Sjfv */ 717222588Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 718222588Sjfv public static double setMonth(final Object self, final Object... args) { 719222588Sjfv final NativeDate nd = getNativeDate(self); 720222588Sjfv setFields(nd, MONTH, args, true); 721222588Sjfv return nd.getTime(); 722222588Sjfv } 723222588Sjfv 724222588Sjfv /** 725222588Sjfv * ECMA 15.9.5.39 Date.prototype.setUTCMonth (month [, date ] ) 726222588Sjfv * 727222588Sjfv * @param self self reference 728222588Sjfv * @param args UTC month (optional second argument is date) 729215911Sjfv * @return time 730215911Sjfv */ 731215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) 732215911Sjfv public static double setUTCMonth(final Object self, final Object... args) { 733215911Sjfv final NativeDate nd = ensureNativeDate(self); 734215911Sjfv setFields(nd, MONTH, args, false); 735215911Sjfv return nd.getTime(); 736215911Sjfv } 737215911Sjfv 738215911Sjfv /** 739215911Sjfv * ECMA 15.9.5.40 Date.prototype.setFullYear (year [, month [, date ] ] ) 740215911Sjfv * 741215911Sjfv * @param self self reference 742215911Sjfv * @param args year (optional second and third arguments are month and date) 743215911Sjfv * @return time 744215911Sjfv */ 745215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) 746215911Sjfv public static double setFullYear(final Object self, final Object... args) { 747215911Sjfv final NativeDate nd = ensureNativeDate(self); 748215911Sjfv if (nd.isValidDate()) { 749215911Sjfv setFields(nd, YEAR, args, true); 750215911Sjfv } else { 751215911Sjfv final double[] d = convertArgs(args, 0, YEAR, YEAR, 3); 752215911Sjfv if (d != null) { 753215911Sjfv nd.setTime(timeClip(utc(makeDate(makeDay(d[0], d[1], d[2]), 0), nd.getTimeZone()))); 754215911Sjfv } else { 755215911Sjfv nd.setTime(NaN); 756215911Sjfv } 757215911Sjfv } 758215911Sjfv return nd.getTime(); 759215911Sjfv } 760215911Sjfv 761215911Sjfv /** 762215911Sjfv * ECMA 15.9.5.41 Date.prototype.setUTCFullYear (year [, month [, date ] ] ) 763215911Sjfv * 764215911Sjfv * @param self self reference 765215911Sjfv * @param args UTC full year (optional second and third arguments are month and date) 766215911Sjfv * @return time 767215911Sjfv */ 768215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) 769215911Sjfv public static double setUTCFullYear(final Object self, final Object... args) { 770215911Sjfv final NativeDate nd = ensureNativeDate(self); 771215911Sjfv if (nd.isValidDate()) { 772215911Sjfv setFields(nd, YEAR, args, false); 773215911Sjfv } else { 774215911Sjfv final double[] d = convertArgs(args, 0, YEAR, YEAR, 3); 775215911Sjfv nd.setTime(timeClip(makeDate(makeDay(d[0], d[1], d[2]), 0))); 776215911Sjfv } 777215911Sjfv return nd.getTime(); 778215911Sjfv } 779215911Sjfv 780215911Sjfv /** 781215911Sjfv * ECMA B.2.5 Date.prototype.setYear (year) 782215911Sjfv * 783215911Sjfv * @param self self reference 784215911Sjfv * @param year year 785215911Sjfv * @return NativeDate 786215911Sjfv */ 787215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 788215911Sjfv public static double setYear(final Object self, final Object year) { 789215911Sjfv final NativeDate nd = getNativeDate(self); 790215911Sjfv if (isNaN(nd.getTime())) { 791215911Sjfv nd.setTime(utc(0, nd.getTimeZone())); 792215911Sjfv } 793215911Sjfv 794215911Sjfv final double yearNum = JSType.toNumber(year); 795215911Sjfv if (isNaN(yearNum)) { 796215911Sjfv nd.setTime(NaN); 797215911Sjfv return nd.getTime(); 798215911Sjfv } 799215911Sjfv int yearInt = (int)yearNum; 800215911Sjfv if (0 <= yearInt && yearInt <= 99) { 801215911Sjfv yearInt += 1900; 802215911Sjfv } 803215911Sjfv setFields(nd, YEAR, new Object[] {yearInt}, true); 804215911Sjfv 805215911Sjfv return nd.getTime(); 806215911Sjfv } 807215911Sjfv 808215911Sjfv /** 809215911Sjfv * ECMA 15.9.5.42 Date.prototype.toUTCString ( ) 810215911Sjfv * 811215911Sjfv * @param self self reference 812215911Sjfv * @return string representation of date 813215911Sjfv */ 814215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 815215911Sjfv public static String toUTCString(final Object self) { 816215911Sjfv return toGMTStringImpl(self); 817215911Sjfv } 818215911Sjfv 819215911Sjfv /** 820215911Sjfv * ECMA B.2.6 Date.prototype.toGMTString ( ) 821215911Sjfv * 822215911Sjfv * See {@link NativeDate#toUTCString(Object)} 823215911Sjfv * 824215911Sjfv * @param self self reference 825215911Sjfv * @return string representation of date 826215911Sjfv */ 827215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 828215911Sjfv public static String toGMTString(final Object self) { 829215911Sjfv return toGMTStringImpl(self); 830215911Sjfv } 831215911Sjfv 832215911Sjfv /** 833215911Sjfv * ECMA 15.9.5.43 Date.prototype.toISOString ( ) 834215911Sjfv * 835215911Sjfv * @param self self reference 836215911Sjfv * @return string representation of date 837215911Sjfv */ 838215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 839215911Sjfv public static String toISOString(final Object self) { 840215911Sjfv return toISOStringImpl(self); 841215911Sjfv } 842215911Sjfv 843215911Sjfv /** 844215911Sjfv * ECMA 15.9.5.44 Date.prototype.toJSON ( key ) 845215911Sjfv * 846215911Sjfv * Provides a string representation of this Date for use by {@link NativeJSON#stringify(Object, Object, Object, Object)} 847215911Sjfv * 848215911Sjfv * @param self self reference 849215911Sjfv * @param key ignored 850215911Sjfv * @return JSON representation of this date 851215911Sjfv */ 852215911Sjfv @Function(attributes = Attribute.NOT_ENUMERABLE) 853215911Sjfv public static Object toJSON(final Object self, final Object key) { 854215911Sjfv // NOTE: Date.prototype.toJSON is generic. Accepts other objects as well. 855215911Sjfv final Object selfObj = Global.toObject(self); 856215911Sjfv if (!(selfObj instanceof ScriptObject)) { 857215911Sjfv return null; 858215911Sjfv } 859215911Sjfv final ScriptObject sobj = (ScriptObject)selfObj; 860215911Sjfv final Object value = sobj.getDefaultValue(Number.class); 861215911Sjfv if (value instanceof Number) { 862215911Sjfv final double num = ((Number)value).doubleValue(); 863215911Sjfv if (isInfinite(num) || isNaN(num)) { 864215911Sjfv return null; 865215911Sjfv } 866215911Sjfv } 867215911Sjfv 868215911Sjfv try { 869215911Sjfv final InvokeByName toIsoString = getTO_ISO_STRING(); 870215911Sjfv final Object func = toIsoString.getGetter().invokeExact(sobj); 871215911Sjfv if (Bootstrap.isCallable(func)) { 872215911Sjfv return toIsoString.getInvoker().invokeExact(func, sobj, key); 873215911Sjfv } 874215911Sjfv throw typeError("not.a.function", ScriptRuntime.safeToString(func)); 875215911Sjfv } catch (final RuntimeException | Error e) { 876215911Sjfv throw e; 877215911Sjfv } catch (final Throwable t) { 878215911Sjfv throw new RuntimeException(t); 879215911Sjfv } 880215911Sjfv } 881215911Sjfv 882215911Sjfv // -- Internals below this point 883215911Sjfv 884215911Sjfv private static double parseDateString(final String str) { 885215911Sjfv 886215911Sjfv final DateParser parser = new DateParser(str); 887215911Sjfv if (parser.parse()) { 888215911Sjfv final Integer[] fields = parser.getDateFields(); 889215911Sjfv double d = makeDate(fields); 890215911Sjfv if (fields[DateParser.TIMEZONE] != null) { 891215911Sjfv d -= fields[DateParser.TIMEZONE] * 60000; 892215911Sjfv } else { 893215911Sjfv d = utc(d, Global.getEnv()._timezone); 894215911Sjfv } 895215911Sjfv d = timeClip(d); 896215911Sjfv return d; 897215911Sjfv } 898215911Sjfv 899215911Sjfv return Double.NaN; 900215911Sjfv } 901215911Sjfv 902215911Sjfv private static void zeroPad(final StringBuilder sb, final int n, final int length) { 903215911Sjfv for (int l = 1, d = 10; l < length; l++, d *= 10) { 904215911Sjfv if (n < d) { 905215911Sjfv sb.append('0'); 906215911Sjfv } 907215911Sjfv } 908215911Sjfv sb.append(n); 909215911Sjfv } 910215911Sjfv 911215911Sjfv @SuppressWarnings("fallthrough") 912215911Sjfv private static String toStringImpl(final Object self, final int format) { 913215911Sjfv final NativeDate nd = getNativeDate(self); 914215911Sjfv 915215911Sjfv if (nd != null && nd.isValidDate()) { 916215911Sjfv final StringBuilder sb = new StringBuilder(40); 917215911Sjfv final double t = nd.getLocalTime(); 918215911Sjfv 919215911Sjfv switch (format) { 920215911Sjfv 921215911Sjfv case FORMAT_DATE_TIME: 922215911Sjfv case FORMAT_DATE : 923215911Sjfv case FORMAT_LOCAL_DATE_TIME: 924215911Sjfv // EEE MMM dd yyyy 925215911Sjfv sb.append(weekDays[weekDay(t)]) 926215911Sjfv .append(' ') 927215911Sjfv .append(months[monthFromTime(t)]) 928215911Sjfv .append(' '); 929215911Sjfv zeroPad(sb, dayFromTime(t), 2); 930215911Sjfv sb.append(' '); 931215911Sjfv zeroPad(sb, yearFromTime(t), 4); 932215911Sjfv if (format == FORMAT_DATE) { 933215911Sjfv break; 934215911Sjfv } 935215911Sjfv sb.append(' '); 936215911Sjfv 937215911Sjfv case FORMAT_TIME: 938215911Sjfv final TimeZone tz = nd.getTimeZone(); 939215911Sjfv final double utcTime = nd.getTime(); 940215911Sjfv int offset = tz.getOffset((long) utcTime) / 60000; 941215911Sjfv final boolean inDaylightTime = offset != tz.getRawOffset() / 60000; 942215911Sjfv // Convert minutes to HHmm timezone offset 943215911Sjfv offset = (offset / 60) * 100 + offset % 60; 944215911Sjfv 945215911Sjfv // HH:mm:ss GMT+HHmm 946215911Sjfv zeroPad(sb, hourFromTime(t), 2); 947215911Sjfv sb.append(':'); 948215911Sjfv zeroPad(sb, minFromTime(t), 2); 949215911Sjfv sb.append(':'); 950215911Sjfv zeroPad(sb, secFromTime(t), 2); 951215911Sjfv sb.append(" GMT") 952215911Sjfv .append(offset < 0 ? '-' : '+'); 953215911Sjfv zeroPad(sb, Math.abs(offset), 4); 954215911Sjfv sb.append(" (") 955215911Sjfv .append(tz.getDisplayName(inDaylightTime, TimeZone.SHORT, Locale.US)) 956215911Sjfv .append(')'); 957215911Sjfv break; 958215911Sjfv 959215911Sjfv case FORMAT_LOCAL_DATE: 960215911Sjfv // yyyy-MM-dd 961215911Sjfv zeroPad(sb, yearFromTime(t), 4); 962215911Sjfv sb.append('-'); 963215911Sjfv zeroPad(sb, monthFromTime(t) + 1, 2); 964215911Sjfv sb.append('-'); 965215911Sjfv zeroPad(sb, dayFromTime(t), 2); 966215911Sjfv break; 967215911Sjfv 968215911Sjfv case FORMAT_LOCAL_TIME: 969215911Sjfv // HH:mm:ss 970215911Sjfv zeroPad(sb, hourFromTime(t), 2); 971215911Sjfv sb.append(':'); 972215911Sjfv zeroPad(sb, minFromTime(t), 2); 973215911Sjfv sb.append(':'); 974215911Sjfv zeroPad(sb, secFromTime(t), 2); 975215911Sjfv break; 976215911Sjfv 977215911Sjfv default: 978215911Sjfv throw new IllegalArgumentException("format: " + format); 979215911Sjfv } 980215911Sjfv 981215911Sjfv return sb.toString(); 982215911Sjfv } 983215911Sjfv 984215911Sjfv return INVALID_DATE; 985215911Sjfv } 986215911Sjfv 987215911Sjfv private static String toGMTStringImpl(final Object self) { 988215911Sjfv final NativeDate nd = getNativeDate(self); 989215911Sjfv 990215911Sjfv if (nd != null && nd.isValidDate()) { 991215911Sjfv final StringBuilder sb = new StringBuilder(29); 992215911Sjfv final double t = nd.getTime(); 993215911Sjfv // EEE, dd MMM yyyy HH:mm:ss z 994215911Sjfv sb.append(weekDays[weekDay(t)]) 995215911Sjfv .append(", "); 996215911Sjfv zeroPad(sb, dayFromTime(t), 2); 997215911Sjfv sb.append(' ') 998215911Sjfv .append(months[monthFromTime(t)]) 999215911Sjfv .append(' '); 1000215911Sjfv zeroPad(sb, yearFromTime(t), 4); 1001215911Sjfv sb.append(' '); 1002215911Sjfv zeroPad(sb, hourFromTime(t), 2); 1003215911Sjfv sb.append(':'); 1004215911Sjfv zeroPad(sb, minFromTime(t), 2); 1005215911Sjfv sb.append(':'); 1006215911Sjfv zeroPad(sb, secFromTime(t), 2); 1007215911Sjfv sb.append(" GMT"); 1008215911Sjfv return sb.toString(); 1009215911Sjfv } 1010215911Sjfv 1011215911Sjfv throw rangeError("invalid.date"); 1012215911Sjfv } 1013215911Sjfv 1014215911Sjfv private static String toISOStringImpl(final Object self) { 1015215911Sjfv final NativeDate nd = getNativeDate(self); 1016215911Sjfv 1017215911Sjfv if (nd != null && nd.isValidDate()) { 1018215911Sjfv final StringBuilder sb = new StringBuilder(24); 1019215911Sjfv final double t = nd.getTime(); 1020215911Sjfv // yyyy-MM-dd'T'HH:mm:ss.SSS'Z' 1021215911Sjfv zeroPad(sb, yearFromTime(t), 4); 1022215911Sjfv sb.append('-'); 1023215911Sjfv zeroPad(sb, monthFromTime(t) + 1, 2); 1024235528Sjfv sb.append('-'); 1025235528Sjfv zeroPad(sb, dayFromTime(t), 2); 1026235528Sjfv sb.append('T'); 1027235528Sjfv zeroPad(sb, hourFromTime(t), 2); 1028235528Sjfv sb.append(':'); 1029235528Sjfv zeroPad(sb, minFromTime(t), 2); 1030235528Sjfv sb.append(':'); 1031235528Sjfv zeroPad(sb, secFromTime(t), 2); 1032235528Sjfv sb.append('.'); 1033235528Sjfv zeroPad(sb, msFromTime(t), 3); 1034235528Sjfv sb.append("Z"); 1035215911Sjfv return sb.toString(); 1036215911Sjfv } 1037215911Sjfv 1038215911Sjfv throw rangeError("invalid.date"); 1039215911Sjfv } 1040215911Sjfv 1041215911Sjfv // ECMA 15.9.1.2 Day (t) 1042215911Sjfv private static double day(final double t) { 1043215911Sjfv return Math.floor(t / msPerDay); 1044215911Sjfv } 1045215911Sjfv 1046215911Sjfv // ECMA 15.9.1.2 TimeWithinDay (t) 1047215911Sjfv private static double timeWithinDay(final double t) { 1048215911Sjfv final double val = t % msPerDay; 1049215911Sjfv return val < 0? val + msPerDay : val; 1050215911Sjfv } 1051215911Sjfv 1052215911Sjfv // ECMA 15.9.1.3 InLeapYear (t) 1053215911Sjfv private static boolean isLeapYear(final int y) { 1054215911Sjfv return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); 1055215911Sjfv } 1056215911Sjfv 1057215911Sjfv // ECMA 15.9.1.3 DaysInYear (y) 1058215911Sjfv private static int daysInYear(final int y) { 1059215911Sjfv return isLeapYear(y) ? 366 : 365; 1060215911Sjfv } 1061215911Sjfv 1062215911Sjfv // ECMA 15.9.1.3 DayFromYear (y) 1063215911Sjfv private static double dayFromYear(final double y) { 1064215911Sjfv return 365 * (y - 1970) 1065215911Sjfv + Math.floor((y -1969) / 4.0) 1066215911Sjfv - Math.floor((y - 1901) / 100.0) 1067215911Sjfv + Math.floor((y - 1601) / 400.0); 1068215911Sjfv } 1069215911Sjfv 1070215911Sjfv // ECMA 15.9.1.3 Year Number 1071215911Sjfv private static double timeFromYear(final int y) { 1072215911Sjfv return dayFromYear(y) * msPerDay; 1073215911Sjfv } 1074215911Sjfv 1075215911Sjfv // ECMA 15.9.1.3 Year Number 1076215911Sjfv private static int yearFromTime(final double t) { 1077215911Sjfv int y = (int) Math.floor(t / (msPerDay * 365.2425)) + 1970; 1078215911Sjfv final double t2 = timeFromYear(y); 1079215911Sjfv if (t2 > t) { 1080215911Sjfv y--; 1081215911Sjfv } else if (t2 + msPerDay * daysInYear(y) <= t) { 1082215911Sjfv y++; 1083215911Sjfv } 1084215911Sjfv return y; 1085215911Sjfv } 1086215911Sjfv 1087215911Sjfv private static int dayWithinYear(final double t, final int year) { 1088215911Sjfv return (int) (day(t) - dayFromYear(year)); 1089215911Sjfv } 1090215911Sjfv 1091215911Sjfv private static int monthFromTime(final double t) { 1092215911Sjfv final int year = yearFromTime(t); 1093215911Sjfv final int day = dayWithinYear(t, year); 1094215911Sjfv final int[] firstDay = firstDayInMonth[isLeapYear(year) ? 1 : 0]; 1095215911Sjfv int month = 0; 1096215911Sjfv 1097215911Sjfv while (month < 11 && firstDay[month + 1] <= day) { 1098215911Sjfv month++; 1099215911Sjfv } 1100215911Sjfv return month; 1101215911Sjfv } 1102215911Sjfv 1103215911Sjfv private static int dayFromTime(final double t) { 1104215911Sjfv final int year = yearFromTime(t); 1105215911Sjfv final int day = dayWithinYear(t, year); 1106215911Sjfv final int[] firstDay = firstDayInMonth[isLeapYear(year) ? 1 : 0]; 1107215911Sjfv int month = 0; 1108215911Sjfv 1109215911Sjfv while (month < 11 && firstDay[month + 1] <= day) { 1110215911Sjfv month++; 1111215911Sjfv } 1112215911Sjfv return 1 + day - firstDay[month]; 1113215911Sjfv } 1114215911Sjfv 1115215911Sjfv private static int dayFromMonth(final int month, final int year) { 1116215911Sjfv assert(month >= 0 && month <= 11); 1117215911Sjfv final int[] firstDay = firstDayInMonth[isLeapYear(year) ? 1 : 0]; 1118215911Sjfv return firstDay[month]; 1119215911Sjfv } 1120215911Sjfv 1121215911Sjfv private static int weekDay(final double time) { 1122215911Sjfv final int day = (int) (day(time) + 4) % 7; 1123215911Sjfv return day < 0 ? day + 7 : day; 1124215911Sjfv } 1125215911Sjfv 1126215911Sjfv // ECMA 15.9.1.9 LocalTime 1127215911Sjfv private static double localTime(final double time, final TimeZone tz) { 1128215911Sjfv return time + tz.getOffset((long) time); 1129215911Sjfv } 1130215911Sjfv 1131215911Sjfv // ECMA 15.9.1.9 UTC 1132215911Sjfv private static double utc(final double time, final TimeZone tz) { 1133215911Sjfv return time - tz.getOffset((long) (time - tz.getRawOffset())); 1134215911Sjfv } 1135215911Sjfv 1136215911Sjfv // ECMA 15.9.1.10 Hours, Minutes, Second, and Milliseconds 1137215911Sjfv private static int hourFromTime(final double t) { 1138215911Sjfv final int h = (int) (Math.floor(t / msPerHour) % hoursPerDay); 1139215911Sjfv return h < 0 ? h + hoursPerDay: h; 1140215911Sjfv } 1141215911Sjfv private static int minFromTime(final double t) { 1142215911Sjfv final int m = (int) (Math.floor(t / msPerMinute) % minutesPerHour); 1143215911Sjfv return m < 0 ? m + minutesPerHour : m; 1144215911Sjfv } 1145215911Sjfv 1146215911Sjfv private static int secFromTime(final double t) { 1147215911Sjfv final int s = (int) (Math.floor(t / msPerSecond) % secondsPerMinute); 1148215911Sjfv return s < 0 ? s + secondsPerMinute : s; 1149215911Sjfv } 1150215911Sjfv 1151215911Sjfv private static int msFromTime(final double t) { 1152215911Sjfv final int m = (int) (t % msPerSecond); 1153215911Sjfv return m < 0 ? m + msPerSecond : m; 1154215911Sjfv } 1155215911Sjfv 1156215911Sjfv private static int valueFromTime(final int unit, final double t) { 1157215911Sjfv switch (unit) { 1158215911Sjfv case YEAR: return yearFromTime(t); 1159215911Sjfv case MONTH: return monthFromTime(t); 1160215911Sjfv case DAY: return dayFromTime(t); 1161215911Sjfv case HOUR: return hourFromTime(t); 1162215911Sjfv case MINUTE: return minFromTime(t); 1163215911Sjfv case SECOND: return secFromTime(t); 1164215911Sjfv case MILLISECOND: return msFromTime(t); 1165215911Sjfv default: throw new IllegalArgumentException(Integer.toString(unit)); 1166215911Sjfv } 1167215911Sjfv } 1168215911Sjfv 1169215911Sjfv // ECMA 15.9.1.11 MakeTime (hour, min, sec, ms) 1170215911Sjfv private static double makeTime(final double hour, final double min, final double sec, final double ms) { 1171215911Sjfv return hour * 3600000 + min * 60000 + sec * 1000 + ms; 1172215911Sjfv } 1173215911Sjfv 1174215911Sjfv // ECMA 15.9.1.12 MakeDay (year, month, date) 1175215911Sjfv private static double makeDay(final double year, final double month, final double date) { 1176215911Sjfv final double y = year + Math.floor(month / 12); 1177215911Sjfv int m = (int) (month % 12); 1178215911Sjfv if (m < 0) { 1179215911Sjfv m += 12; 1180215911Sjfv } 1181215911Sjfv double d = dayFromYear(y); 1182215911Sjfv d += dayFromMonth(m, (int) y); 1183215911Sjfv 1184215911Sjfv return d + date - 1; 1185215911Sjfv } 1186215911Sjfv 1187215911Sjfv // ECMA 15.9.1.13 MakeDate (day, time) 1188215911Sjfv private static double makeDate(final double day, final double time) { 1189215911Sjfv return day * msPerDay + time; 1190215911Sjfv } 1191215911Sjfv 1192215911Sjfv 1193215911Sjfv private static double makeDate(final Integer[] d) { 1194215911Sjfv final double time = makeDay(d[0], d[1], d[2]) * msPerDay; 1195215911Sjfv return time + makeTime(d[3], d[4], d[5], d[6]); 1196215911Sjfv } 1197215911Sjfv 1198215911Sjfv private static double makeDate(final double[] d) { 1199215911Sjfv final double time = makeDay(d[0], d[1], d[2]) * msPerDay; 1200215911Sjfv return time + makeTime(d[3], d[4], d[5], d[6]); 1201215911Sjfv } 1202215911Sjfv 1203215911Sjfv // Convert Date constructor args, checking for NaN, filling in defaults etc. 1204215911Sjfv private static double[] convertCtorArgs(final Object[] args) { 1205215911Sjfv final double[] d = new double[7]; 1206215911Sjfv boolean nullReturn = false; 1207235528Sjfv 1208215911Sjfv // should not bailout on first NaN or infinite. Need to convert all 1209215911Sjfv // subsequent args for possible side-effects via valueOf/toString overrides 1210215911Sjfv // on argument objects. 1211215911Sjfv for (int i = 0; i < d.length; i++) { 1212215911Sjfv if (i < args.length) { 1213215911Sjfv final double darg = JSType.toNumber(args[i]); 1214215911Sjfv if (isNaN(darg) || isInfinite(darg)) { 1215215911Sjfv nullReturn = true; 1216215911Sjfv } 1217215911Sjfv 1218215911Sjfv d[i] = (long)darg; 1219215911Sjfv } else { 1220215911Sjfv d[i] = i == 2 ? 1 : 0; // day in month defaults to 1 1221215911Sjfv } 1222215911Sjfv } 1223215911Sjfv 1224215911Sjfv if (0 <= d[0] && d[0] <= 99) { 1225215911Sjfv d[0] += 1900; 1226235528Sjfv } 1227215911Sjfv 1228215911Sjfv return nullReturn? null : d; 1229215911Sjfv } 1230215911Sjfv 1231215911Sjfv // This method does the hard work for all setter methods: If a value is provided 1232215911Sjfv // as argument it is used, otherwise the value is calculated from the existing time value. 1233215911Sjfv private static double[] convertArgs(final Object[] args, final double time, final int fieldId, final int start, final int length) { 1234215911Sjfv final double[] d = new double[length]; 1235215911Sjfv boolean nullReturn = false; 1236215911Sjfv 1237215911Sjfv // Need to call toNumber on all args for side-effects - even if an argument 1238248078Smarius // fails to convert to number, subsequent toNumber calls needed for possible 1239215911Sjfv // side-effects via valueOf/toString overrides. 1240215911Sjfv for (int i = start; i < start + length; i++) { 1241215911Sjfv if (fieldId <= i && i < fieldId + args.length) { 1242215911Sjfv final double darg = JSType.toNumber(args[i - fieldId]); 1243215911Sjfv if (isNaN(darg) || isInfinite(darg)) { 1244215911Sjfv nullReturn = true; 1245215911Sjfv } 1246215911Sjfv 1247215911Sjfv d[i - start] = (long) darg; 1248215911Sjfv } else { 1249215911Sjfv // Date.prototype.set* methods require first argument to be defined 1250215911Sjfv if (i == fieldId) { 1251215911Sjfv nullReturn = true; 1252215911Sjfv } 1253215911Sjfv 1254215911Sjfv if (!nullReturn && !isNaN(time)) { 1255215911Sjfv d[i - start] = valueFromTime(i, time); 1256215911Sjfv } 1257215911Sjfv } 1258215911Sjfv } 1259215911Sjfv 1260215911Sjfv return nullReturn ? null : d; 1261215911Sjfv } 1262215911Sjfv 1263215911Sjfv // ECMA 15.9.1.14 TimeClip (time) 1264215911Sjfv private static double timeClip(final double time) { 1265215911Sjfv if (isInfinite(time) || isNaN(time) || Math.abs(time) > 8.64e15) { 1266215911Sjfv return Double.NaN; 1267215911Sjfv } 1268215911Sjfv return (long)time; 1269215911Sjfv } 1270215911Sjfv 1271215911Sjfv private static NativeDate ensureNativeDate(final Object self) { 1272215911Sjfv return getNativeDate(self); 1273215911Sjfv } 1274215911Sjfv 1275215911Sjfv private static NativeDate getNativeDate(final Object self) { 1276215911Sjfv if (self instanceof NativeDate) { 1277215911Sjfv return (NativeDate)self; 1278215911Sjfv } else if (self != null && self == Global.instance().getDatePrototype()) { 1279215911Sjfv return Global.instance().DEFAULT_DATE; 1280215911Sjfv } else { 1281215911Sjfv throw typeError("not.a.date", ScriptRuntime.safeToString(self)); 1282215911Sjfv } 1283215911Sjfv } 1284215911Sjfv 1285215911Sjfv private static double getField(final Object self, final int field) { 1286215911Sjfv final NativeDate nd = getNativeDate(self); 1287215911Sjfv return (nd != null && nd.isValidDate()) ? (double)valueFromTime(field, nd.getLocalTime()) : Double.NaN; 1288215911Sjfv } 1289215911Sjfv 1290215911Sjfv private static double getUTCField(final Object self, final int field) { 1291215911Sjfv final NativeDate nd = getNativeDate(self); 1292215911Sjfv return (nd != null && nd.isValidDate()) ? (double)valueFromTime(field, nd.getTime()) : Double.NaN; 1293215911Sjfv } 1294215911Sjfv 1295215911Sjfv private static void setFields(final NativeDate nd, final int fieldId, final Object[] args, final boolean local) { 1296215911Sjfv int start, length; 1297215911Sjfv if (fieldId < HOUR) { 1298215911Sjfv start = YEAR; 1299215911Sjfv length = 3; 1300215911Sjfv } else { 1301215911Sjfv start = HOUR; 1302215911Sjfv length = 4; 1303215911Sjfv } 1304215911Sjfv final double time = local ? nd.getLocalTime() : nd.getTime(); 1305215911Sjfv final double d[] = convertArgs(args, time, fieldId, start, length); 1306215911Sjfv 1307215911Sjfv if (! nd.isValidDate()) { 1308215911Sjfv return; 1309215911Sjfv } 1310215911Sjfv 1311215911Sjfv double newTime; 1312215911Sjfv if (d == null) { 1313215911Sjfv newTime = NaN; 1314215911Sjfv } else { 1315215911Sjfv if (start == YEAR) { 1316215911Sjfv newTime = makeDate(makeDay(d[0], d[1], d[2]), timeWithinDay(time)); 1317215911Sjfv } else { 1318215911Sjfv newTime = makeDate(day(time), makeTime(d[0], d[1], d[2], d[3])); 1319215911Sjfv } 1320215911Sjfv if (local) { 1321215911Sjfv newTime = utc(newTime, nd.getTimeZone()); 1322215911Sjfv } 1323215911Sjfv newTime = timeClip(newTime); 1324215911Sjfv } 1325215911Sjfv nd.setTime(newTime); 1326215911Sjfv } 1327215911Sjfv 1328215911Sjfv private boolean isValidDate() { 1329222588Sjfv return !isNaN(time); 1330215911Sjfv } 1331215911Sjfv 1332215911Sjfv private double getLocalTime() { 1333215911Sjfv return localTime(time, timezone); 1334215911Sjfv } 1335215911Sjfv 1336215911Sjfv private double getTime() { 1337215911Sjfv return time; 1338215911Sjfv } 1339215911Sjfv 1340215911Sjfv private void setTime(final double time) { 1341215911Sjfv this.time = time; 1342215911Sjfv } 1343215911Sjfv 1344215911Sjfv private TimeZone getTimeZone() { 1345215911Sjfv return timezone; 1346215911Sjfv } 1347215911Sjfv} 1348215911Sjfv