/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.runtime.objects.date;
import static com.github.anba.es6draft.runtime.AbstractOperations.ToFlatString;
import static com.github.anba.es6draft.runtime.AbstractOperations.ToInteger;
import static com.github.anba.es6draft.runtime.AbstractOperations.ToNumber;
import static com.github.anba.es6draft.runtime.AbstractOperations.ToPrimitive;
import static com.github.anba.es6draft.runtime.internal.Errors.newTypeError;
import static com.github.anba.es6draft.runtime.internal.Properties.createProperties;
import static com.github.anba.es6draft.runtime.objects.date.DateAbstractOperations.*;
import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.internal.Initializable;
import com.github.anba.es6draft.runtime.internal.Messages;
import com.github.anba.es6draft.runtime.internal.Properties.Attributes;
import com.github.anba.es6draft.runtime.internal.Properties.Function;
import com.github.anba.es6draft.runtime.internal.Properties.Optional;
import com.github.anba.es6draft.runtime.internal.Properties.Optional.Default;
import com.github.anba.es6draft.runtime.internal.Properties.Prototype;
import com.github.anba.es6draft.runtime.internal.Properties.Value;
import com.github.anba.es6draft.runtime.objects.date.DatePrototype.DateString;
import com.github.anba.es6draft.runtime.types.Constructor;
import com.github.anba.es6draft.runtime.types.Intrinsics;
import com.github.anba.es6draft.runtime.types.Type;
import com.github.anba.es6draft.runtime.types.builtins.BuiltinConstructor;
/**
* <h1>20 Numbers and Dates</h1><br>
* <h2>20.3 Date Objects</h2>
* <ul>
* <li>20.3.2 The Date Constructor
* <li>20.3.3 Properties of the Date Constructor
* </ul>
*/
public final class DateConstructor extends BuiltinConstructor implements Initializable {
/**
* Constructs a new Date constructor function.
*
* @param realm
* the realm object
*/
public DateConstructor(Realm realm) {
super(realm, "Date", 7);
}
@Override
public void initialize(Realm realm) {
createProperties(realm, this, Properties.class);
}
@Override
public DateConstructor clone() {
return new DateConstructor(getRealm());
}
/**
* 20.3.2.1 Date (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )<br>
* 20.3.2.2 Date (value)<br>
* 20.3.2.3 Date ( )<br>
*/
@Override
public String call(ExecutionContext callerContext, Object thisValue, Object... args) {
ExecutionContext calleeContext = calleeContext();
/* steps 1-3 (not applicable) */
/* step 4 */
long now = System.currentTimeMillis();
return DatePrototype.ToDateString(calleeContext.getRealm(), now, DateString.DateTime);
}
/**
* 20.3.2.1 Date (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )<br>
* 20.3.2.2 Date (value)<br>
* 20.3.2.3 Date ( )<br>
*/
@Override
public DateObject construct(ExecutionContext callerContext, Constructor newTarget,
Object... args) {
ExecutionContext calleeContext = calleeContext();
Realm realm = calleeContext.getRealm();
/* steps 1-2 */
int numberOfArgs = args.length;
/* step 3 */
final double dateValue;
if (numberOfArgs >= 2) {
// [20.3.2.1]
double year = ToNumber(calleeContext, args[0]);
double month = ToNumber(calleeContext, args[1]);
double date = (args.length > 2 ? ToNumber(calleeContext, args[2]) : 1);
double hour = (args.length > 3 ? ToNumber(calleeContext, args[3]) : 0);
double min = (args.length > 4 ? ToNumber(calleeContext, args[4]) : 0);
double sec = (args.length > 5 ? ToNumber(calleeContext, args[5]) : 0);
double ms = (args.length > 6 ? ToNumber(calleeContext, args[6]) : 0);
if (!Double.isNaN(year) && 0 <= ToInteger(year) && ToInteger(year) <= 99) {
year = 1900 + ToInteger(year);
}
double finalDate = MakeDate(MakeDay(year, month, date), MakeTime(hour, min, sec, ms));
dateValue = TimeClip(UTC(realm, finalDate));
} else if (numberOfArgs == 1) {
// [20.3.2.2]
double tv;
if (args[0] instanceof DateObject) {
tv = thisTimeValue(calleeContext, args[0]);
} else {
Object v = ToPrimitive(calleeContext, args[0]);
if (Type.isString(v)) {
tv = (double) Properties.parse(calleeContext, null, v);
} else {
tv = ToNumber(calleeContext, v);
}
}
dateValue = TimeClip(tv);
} else {
// [20.3.2.3]
dateValue = System.currentTimeMillis();
}
DateObject obj = OrdinaryCreateFromConstructor(calleeContext, newTarget, Intrinsics.DatePrototype,
DateObject::new);
obj.setDateValue(dateValue);
return obj;
/* step 4 (not applicable) */
}
/**
* Abstract operation thisTimeValue(value)
*
* @param cx
* the execution context
* @param object
* the date object
* @return the date-time value
*/
private static double thisTimeValue(ExecutionContext cx, Object object) {
if (object instanceof DateObject) {
return ((DateObject) object).getDateValue();
}
throw newTypeError(cx, Messages.Key.IncompatibleObject);
}
/**
* 20.3.3 Properties of the Date Constructor
*/
public enum Properties {
;
@Prototype
public static final Intrinsics __proto__ = Intrinsics.FunctionPrototype;
@Value(name = "length", attributes = @Attributes(writable = false, enumerable = false,
configurable = true))
public static final int length = 7;
@Value(name = "name", attributes = @Attributes(writable = false, enumerable = false,
configurable = true))
public static final String name = "Date";
/**
* 20.3.3.3 Date.prototype
*/
@Value(name = "prototype", attributes = @Attributes(writable = false, enumerable = false,
configurable = false))
public static final Intrinsics prototype = Intrinsics.DatePrototype;
/**
* 20.3.3.2 Date.parse (string)
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param string
* the date string
* @return the parsed date value
*/
@Function(name = "parse", arity = 1)
public static Object parse(ExecutionContext cx, Object thisValue, Object string) {
String s = ToFlatString(cx, string);
double d = parseISOString(cx.getRealm(), s, true);
if (Double.isNaN(d)) {
d = parseDateString(cx.getRealm(), s);
}
return d;
}
/**
* 20.3.3.4 Date.UTC (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param year
* the year value
* @param month
* the month value
* @param date
* the date value
* @param hours
* the hours value
* @param minutes
* the minutes value
* @param seconds
* the seconds value
* @param ms
* the milli-seconds value
* @return the new date object
*/
@Function(name = "UTC", arity = 7)
public static Object UTC(ExecutionContext cx, Object thisValue, Object year, Object month,
@Optional(value = Default.Number, numberValue = 1) Object date, @Optional(
value = Default.Number, numberValue = 0) Object hours, @Optional(
value = Default.Number, numberValue = 0) Object minutes, @Optional(
value = Default.Number, numberValue = 0) Object seconds, @Optional(
value = Default.Number, numberValue = 0) Object ms) {
/* steps 1-2 */
double y = ToNumber(cx, year);
/* steps 3-4 */
double m = ToNumber(cx, month);
/* steps 5-6 */
double dt = ToNumber(cx, date);
/* steps 7-8 */
double h = ToNumber(cx, hours);
/* steps 9-10 */
double min = ToNumber(cx, minutes);
/* steps 11-12 */
double sec = ToNumber(cx, seconds);
/* steps 13-14 */
double milli = ToNumber(cx, ms);
/* step 15 */
if (!Double.isNaN(y) && 0 <= ToInteger(y) && ToInteger(y) <= 99) {
y = 1900 + ToInteger(y);
}
/* step 16 */
return TimeClip(MakeDate(MakeDay(y, m, dt), MakeTime(h, min, sec, milli)));
}
/**
* 20.3.3.1 Date.now ( )
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @return the current date in milli-seconds since the epoch
*/
@Function(name = "now", arity = 0)
public static Object now(ExecutionContext cx, Object thisValue) {
return (double) System.currentTimeMillis();
}
}
}