827 * 828 * @param self self reference 829 * @return string representation of date 830 */ 831 @Function(attributes = Attribute.NOT_ENUMERABLE) 832 public static Object toISOString(final Object self) { 833 return toISOStringImpl(self); 834 } 835 836 /** 837 * ECMA 15.9.5.44 Date.prototype.toJSON ( key ) 838 * 839 * Provides a string representation of this Date for use by {@link NativeJSON#stringify(Object, Object, Object, Object)} 840 * 841 * @param self self reference 842 * @param key ignored 843 * @return JSON representation of this date 844 */ 845 @Function(attributes = Attribute.NOT_ENUMERABLE) 846 public static Object toJSON(final Object self, final Object key) { 847 if (self instanceof NativeDate) { 848 final NativeDate nd = (NativeDate)self; 849 return (isNaN(nd.getTime())) ? null : toISOStringImpl(nd); 850 } 851 // NOTE: Date.prototype.toJSON is generic. Accepts other objects as well. 852 final Object selfObj = Global.toObject(self); 853 if (!(selfObj instanceof ScriptObject)) { 854 return null; 855 } 856 final ScriptObject sobj = (ScriptObject)selfObj; 857 final Object value = sobj.getDefaultValue(Number.class); 858 859 final double num = (value instanceof Number) ? ((Number)value).doubleValue() : NaN; 860 861 if (isInfinite(num) || isNaN(num)) { 862 return null; 863 } 864 865 try { 866 final Object func = TO_ISO_STRING.getGetter().invokeExact(sobj); 867 if (func instanceof ScriptFunction) { 868 return TO_ISO_STRING.getInvoker().invokeExact(func, sobj, key); 869 } 870 throw typeError("not.a.function", ScriptRuntime.safeToString(func)); 1183 1184 // ECMA 15.9.1.13 MakeDate (day, time) 1185 private static double makeDate(final double day, final double time) { 1186 return day * msPerDay + time; 1187 } 1188 1189 1190 private static double makeDate(final Integer[] d) { 1191 final double time = makeDay(d[0], d[1], d[2]) * msPerDay; 1192 return time + makeTime(d[3], d[4], d[5], d[6]); 1193 } 1194 1195 private static double makeDate(final double[] d) { 1196 final double time = makeDay(d[0], d[1], d[2]) * msPerDay; 1197 return time + makeTime(d[3], d[4], d[5], d[6]); 1198 } 1199 1200 // Convert Date constructor args, checking for NaN, filling in defaults etc. 1201 private static double[] convertCtorArgs(final Object[] args) { 1202 final double[] d = new double[7]; 1203 1204 for (int i = 0; i < d.length; i++) { 1205 if (i < args.length) { 1206 final double darg = JSType.toNumber(args[i]); 1207 if (isNaN(darg) || isInfinite(darg)) { 1208 return null; 1209 } 1210 d[i] = (long)darg; 1211 } else { 1212 d[i] = i == 2 ? 1 : 0; // day in month defaults to 1 1213 } 1214 } 1215 1216 if (0 <= d[0] && d[0] <= 99) { 1217 d[0] += 1900; 1218 } 1219 1220 return d; 1221 } 1222 1223 // This method does the hard work for all setter methods: If a value is provided 1224 // as argument it is used, otherwise the value is calculated from the existing time value. 1225 private static double[] convertArgs(final Object[] args, final double time, final int fieldId, final int start, final int length) { 1226 final double[] d = new double[length]; 1227 1228 for (int i = start; i < start + length; i++) { 1229 if (fieldId <= i && i < fieldId + args.length) { 1230 final double darg = JSType.toNumber(args[i - fieldId]); 1231 if (isNaN(darg) || isInfinite(darg)) { 1232 return null; 1233 } 1234 d[i - start] = (long) darg; 1235 } else { 1236 // Date.prototype.set* methods require first argument to be defined 1237 if (i == fieldId) { 1238 return null; 1239 } 1240 d[i - start] = valueFromTime(i, time); 1241 } 1242 } 1243 return d; 1244 1245 } 1246 1247 // ECMA 15.9.1.14 TimeClip (time) 1248 private static double timeClip(final double time) { 1249 if (isInfinite(time) || isNaN(time) || Math.abs(time) > 8.64e15) { 1250 return Double.NaN; 1251 } 1252 return (long)time; 1253 } 1254 1255 private static NativeDate ensureNativeDate(final Object self) { 1256 return getNativeDate(self); 1257 } 1258 1259 private static NativeDate getNativeDate(final Object self) { 1260 if (self instanceof NativeDate) { 1261 return (NativeDate)self; 1262 } else if (self != null && self == Global.instance().getDatePrototype()) { 1263 return Global.instance().DEFAULT_DATE; 1264 } else { | 827 * 828 * @param self self reference 829 * @return string representation of date 830 */ 831 @Function(attributes = Attribute.NOT_ENUMERABLE) 832 public static Object toISOString(final Object self) { 833 return toISOStringImpl(self); 834 } 835 836 /** 837 * ECMA 15.9.5.44 Date.prototype.toJSON ( key ) 838 * 839 * Provides a string representation of this Date for use by {@link NativeJSON#stringify(Object, Object, Object, Object)} 840 * 841 * @param self self reference 842 * @param key ignored 843 * @return JSON representation of this date 844 */ 845 @Function(attributes = Attribute.NOT_ENUMERABLE) 846 public static Object toJSON(final Object self, final Object key) { 847 // NOTE: Date.prototype.toJSON is generic. Accepts other objects as well. 848 final Object selfObj = Global.toObject(self); 849 if (!(selfObj instanceof ScriptObject)) { 850 return null; 851 } 852 final ScriptObject sobj = (ScriptObject)selfObj; 853 final Object value = sobj.getDefaultValue(Number.class); 854 855 final double num = (value instanceof Number) ? ((Number)value).doubleValue() : NaN; 856 857 if (isInfinite(num) || isNaN(num)) { 858 return null; 859 } 860 861 try { 862 final Object func = TO_ISO_STRING.getGetter().invokeExact(sobj); 863 if (func instanceof ScriptFunction) { 864 return TO_ISO_STRING.getInvoker().invokeExact(func, sobj, key); 865 } 866 throw typeError("not.a.function", ScriptRuntime.safeToString(func)); 1179 1180 // ECMA 15.9.1.13 MakeDate (day, time) 1181 private static double makeDate(final double day, final double time) { 1182 return day * msPerDay + time; 1183 } 1184 1185 1186 private static double makeDate(final Integer[] d) { 1187 final double time = makeDay(d[0], d[1], d[2]) * msPerDay; 1188 return time + makeTime(d[3], d[4], d[5], d[6]); 1189 } 1190 1191 private static double makeDate(final double[] d) { 1192 final double time = makeDay(d[0], d[1], d[2]) * msPerDay; 1193 return time + makeTime(d[3], d[4], d[5], d[6]); 1194 } 1195 1196 // Convert Date constructor args, checking for NaN, filling in defaults etc. 1197 private static double[] convertCtorArgs(final Object[] args) { 1198 final double[] d = new double[7]; 1199 boolean nullReturn = false; 1200 1201 // should not bailout on first NaN or infinite. Need to convert all 1202 // subsequent args for possible side-effects via valueOf/toString overrides 1203 // on argument objects. 1204 for (int i = 0; i < d.length; i++) { 1205 if (i < args.length) { 1206 final double darg = JSType.toNumber(args[i]); 1207 if (isNaN(darg) || isInfinite(darg)) { 1208 nullReturn = true; 1209 } 1210 1211 d[i] = (long)darg; 1212 } else { 1213 d[i] = i == 2 ? 1 : 0; // day in month defaults to 1 1214 } 1215 } 1216 1217 if (0 <= d[0] && d[0] <= 99) { 1218 d[0] += 1900; 1219 } 1220 1221 return nullReturn? null : d; 1222 } 1223 1224 // This method does the hard work for all setter methods: If a value is provided 1225 // as argument it is used, otherwise the value is calculated from the existing time value. 1226 private static double[] convertArgs(final Object[] args, final double time, final int fieldId, final int start, final int length) { 1227 final double[] d = new double[length]; 1228 boolean nullReturn = false; 1229 1230 // Need to call toNumber on all args for side-effects - even if an argument 1231 // fails to convert to number, subsequent toNumber calls needed for possible 1232 // side-effects via valueOf/toString overrides. 1233 for (int i = start; i < start + length; i++) { 1234 if (fieldId <= i && i < fieldId + args.length) { 1235 final double darg = JSType.toNumber(args[i - fieldId]); 1236 if (isNaN(darg) || isInfinite(darg)) { 1237 nullReturn = true; 1238 } 1239 1240 d[i - start] = (long) darg; 1241 } else { 1242 // Date.prototype.set* methods require first argument to be defined 1243 if (i == fieldId) { 1244 nullReturn = true; 1245 } 1246 1247 if (! nullReturn) { 1248 d[i - start] = valueFromTime(i, time); 1249 } 1250 } 1251 } 1252 1253 return nullReturn? null : d; 1254 } 1255 1256 // ECMA 15.9.1.14 TimeClip (time) 1257 private static double timeClip(final double time) { 1258 if (isInfinite(time) || isNaN(time) || Math.abs(time) > 8.64e15) { 1259 return Double.NaN; 1260 } 1261 return (long)time; 1262 } 1263 1264 private static NativeDate ensureNativeDate(final Object self) { 1265 return getNativeDate(self); 1266 } 1267 1268 private static NativeDate getNativeDate(final Object self) { 1269 if (self instanceof NativeDate) { 1270 return (NativeDate)self; 1271 } else if (self != null && self == Global.instance().getDatePrototype()) { 1272 return Global.instance().DEFAULT_DATE; 1273 } else { |