Skip to content

Commit

Permalink
Normative: Remove epoch seconds and epoch microseconds APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
ptomato committed May 24, 2024
1 parent 69c9152 commit 6fce96c
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 210 deletions.
3 changes: 1 addition & 2 deletions docs/ambiguity.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,10 @@ dateTime = Temporal.PlainDateTime.from('2019-12-17T07:48');
zdt = dateTime.toZonedDateTime('Asia/Tokyo');
// => 2019-12-17T07:48:00+09:00[Asia/Tokyo]

// Get the exact time in seconds, milliseconds, or nanoseconds since the UNIX epoch.
// Get the exact time in milliseconds or nanoseconds since the UNIX epoch.
inst = zdt.toInstant();
epochNano = inst.epochNanoseconds; // => 1576536480000000000n
epochMilli = inst.epochMilliseconds; // => 1576536480000
epochSecs = inst.epochSeconds; // => 1576536480
```
<!-- prettier-ignore-end -->

Expand Down
2 changes: 0 additions & 2 deletions docs/cookbook/getTimeStamp.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,3 @@ const timeStamp = Temporal.Now.instant();

// Timestamp in Milliseconds
timeStamp.epochMilliseconds;
// Timestamp in Seconds
timeStamp.epochSeconds;
105 changes: 40 additions & 65 deletions docs/instant.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,39 +134,20 @@ instant === Temporal.Instant.from(instant); // => false
```
<!-- prettier-ignore-end -->

### Temporal.Instant.**fromEpochSeconds**(_epochSeconds_: number) : Temporal.Instant
### Temporal.Instant.**fromEpochMilliseconds**(_epochMilliseconds_: number) : Temporal.Instant

**Parameters:**

- `epochSeconds` (number): A number of seconds.
- `epochMilliseconds` (number): A number of milliseconds.

**Returns:** a new `Temporal.Instant` object.

This static method creates a new `Temporal.Instant` object with seconds precision.
`epochSeconds` is the number of seconds between the Unix epoch (midnight UTC on January 1, 1970) and the desired exact time.
This static method creates a new `Temporal.Instant` object with milliseconds precision.
`epochMilliseconds` is the number of milliseconds between the Unix epoch (midnight UTC on January 1, 1970) and the desired exact time.

The number of seconds since the Unix epoch is a common measure of exact time in many computer systems.
Use this method if you need to interface with such a system.

Example usage:

```js
// Same examples as in new Temporal.Instant(), but with seconds precision
instant = Temporal.Instant.fromEpochSeconds(1553906700);
epoch = Temporal.Instant.fromEpochSeconds(0); // => 1970-01-01T00:00:00Z
turnOfTheCentury = Temporal.Instant.fromEpochSeconds(-2208988800); // => 1900-01-01T00:00:00Z
```

### Temporal.Instant.**fromEpochMilliseconds**(_epochMilliseconds_: number) : Temporal.Instant

**Parameters:**

- `epochMilliseconds` (number): A number of milliseconds.

**Returns:** a new `Temporal.Instant` object.

Same as `Temporal.Instant.fromEpochSeconds()`, but with millisecond (10<sup>&minus;3</sup> second) precision.

The number of milliseconds since the Unix epoch is also returned from the `getTime()` and `valueOf()` methods of legacy JavaScript `Date` objects, as well as `Date.now()`.
However, for conversion from legacy `Date` to `Temporal.Instant`, use `Date.prototype.toTemporalInstant`:

Expand All @@ -178,17 +159,11 @@ instant = legacyDate.toTemporalInstant(); // recommended

// Use fromEpochMilliseconds, for example, if you have epoch millisecond data stored in a file
todayMs = Temporal.Instant.fromEpochMilliseconds(msReadFromFile);
```

### Temporal.Instant.**fromEpochMicroseconds**(_epochMicroseconds_ : bigint) : Temporal.Instant

**Parameters:**

- `epochMicroseconds` (bigint): A number of microseconds.

**Returns:** a new `Temporal.Instant` object.

Same as `Temporal.Instant.fromEpochSeconds()`, but with microsecond (10<sup>&minus;6</sup> second) precision.
// If you have epoch seconds data:
epochSecs = 1553906700; // e.g., read from a file
instant = Temporal.Instant.fromEpochMilliseconds(epochSecs * 1000);
```

### Temporal.Instant.**fromEpochNanoseconds**(_epochNanoseconds_ : bigint) : Temporal.Instant

Expand All @@ -198,9 +173,15 @@ Same as `Temporal.Instant.fromEpochSeconds()`, but with microsecond (10<sup>&min

**Returns:** a new `Temporal.Instant` object.

Same as `Temporal.Instant.fromEpochSeconds()`, but with nanosecond (10<sup>&minus;9</sup> second) precision.
Same as `Temporal.Instant.fromEpochMilliseconds()`, but with nanosecond (10<sup>&minus;9</sup> second) precision.
Also the same as `new Temporal.Instant(epochNanoseconds)`.

If you have epoch microseconds data, you can use this function to create a `Temporal.Instant` from that:
```js
epochMicros = 1553906700_000_000n;
instant = Temporal.Instant.fromEpochNanoseconds(epochMicros * 1000n);
```

### Temporal.Instant.**compare**(_one_: Temporal.Instant | string, _two_: Temporal.Instant | string) : number

**Parameters:**
Expand All @@ -223,55 +204,49 @@ This function can be used to sort arrays of `Temporal.Instant` objects.
For example:

```javascript
one = Temporal.Instant.fromEpochSeconds(1.0e9);
two = Temporal.Instant.fromEpochSeconds(1.1e9);
three = Temporal.Instant.fromEpochSeconds(1.2e9);
one = Temporal.Instant.fromEpochMilliseconds(1.0e12);
two = Temporal.Instant.fromEpochMilliseconds(1.1e12);
three = Temporal.Instant.fromEpochMilliseconds(1.2e12);
sorted = [three, one, two].sort(Temporal.Instant.compare);
sorted.join(' ');
// => '2001-09-09T01:46:40Z 2004-11-09T11:33:20Z 2008-01-10T21:20:00Z'
```

## Properties

### instant.**epochSeconds** : number
### instant.**epochMilliseconds** : number

The value of this property is an integer number of seconds between the Unix epoch (midnight UTC on January 1, 1970) and `instant`.
The value of this property is an integer number of milliseconds between the Unix epoch (midnight UTC on January 1, 1970) and `instant`.
This number will be negative if `instant` is before 1970.
The number of seconds is truncated towards zero.

Use this property if you need to interface with some other system that reckons time in seconds since the Unix epoch.

Example usage:

```js
instant = Temporal.Instant.from('2019-03-30T01:45+01:00');
instant.epochSeconds; // => 1553906700
```

### instant.**epochMilliseconds** : number
The number of milliseconds is truncated towards the beginning of time.

Same as `epochSeconds`, but with millisecond (10<sup>&minus;3</sup> second) precision.
The number of seconds is truncated towards zero.
Use this property if you need to interface with some other system that reckons time in milliseconds since the Unix epoch.

This method can be useful in particular to create an old-style JavaScript `Date` object, if one is needed.
An example:

```js
instant = Temporal.Instant.from('2019-03-30T00:45Z');
new Date(instant.epochMilliseconds); // => 2019-03-30T00:45:00.000Z
```

### instant.**epochMicroseconds** : bigint

Same as `epochSeconds`, but the value is a bigint with microsecond (10<sup>&minus;6</sup> second) precision.
The number of seconds is truncated towards zero.
// If you need epoch seconds data:
epochSecs = Math.floor(instant.epochMillieconds / 1000); // => 1553906700
```

### instant.**epochNanoseconds** : bigint

Same as `epochSeconds`, but the value is a bigint with nanosecond (10<sup>&minus;9</sup> second) precision.
Same as `epochMilliseconds`, but the value is a bigint with nanosecond (10<sup>&minus;9</sup> second) precision.

The value of this property is suitable to be passed to `new Temporal.Instant()`.

If you need epoch microseconds data, you can divide the epoch nanoseconds by 1000, but note that bigint division is a truncation, whereas you should use floor rounding to calculate epoch microseconds in the case of a negative value.
That can be done with bigints like this:

```js
ns = instant.epochNanoseconds;
epochMicros = ns / 1000n + ((ns % 1000n) < 0n ? -1n : 0n);
```

## Methods

### instant.**toZonedDateTimeISO**(_timeZone_: object | string) : Temporal.ZonedDateTime
Expand All @@ -297,7 +272,7 @@ Example usage:

```js
// Converting a specific exact time to a calendar date / wall-clock time
timestamp = Temporal.Instant.fromEpochSeconds(1553993100);
timestamp = Temporal.Instant.fromEpochMilliseconds(1553993100_000);
timestamp.toZonedDateTimeISO('Europe/Berlin'); // => 2019-03-31T01:45:00+01:00[Europe/Berlin]
timestamp.toZonedDateTimeISO('UTC'); // => 2019-03-31T00:45:00+00:00[UTC]
timestamp.toZonedDateTimeISO('-08:00'); // => 2019-03-30T16:45:00-08:00[-08:00]
Expand Down Expand Up @@ -325,7 +300,7 @@ Example usage:
<!-- prettier-ignore-start -->
```js
// What time was the Unix epoch (timestamp 0) in Bell Labs (Murray Hill, New Jersey, USA) in the Gregorian calendar?
epoch = Temporal.Instant.fromEpochSeconds(0);
epoch = Temporal.Instant.fromEpochMilliseconds(0);
timeZone = Temporal.TimeZone.from('America/New_York');
epoch.toZonedDateTime({ timeZone, calendar: 'gregory' });
// => 1969-12-31T19:00:00-05:00[America/New_York][u-ca=gregory]
Expand Down Expand Up @@ -446,8 +421,8 @@ approxMissionLength = startOfMoonMission.until(endOfMoonMission, {
// => PT195H

// A billion (10^9) seconds since the epoch in different units
epoch = Temporal.Instant.fromEpochSeconds(0);
billion = Temporal.Instant.fromEpochSeconds(1e9);
epoch = Temporal.Instant.fromEpochMilliseconds(0);
billion = Temporal.Instant.fromEpochMilliseconds(1e9);
epoch.until(billion);
// => PT1000000000S
epoch.until(billion, { largestUnit: 'hour' });
Expand Down Expand Up @@ -552,8 +527,8 @@ If `other` is not a `Temporal.Instant` object, then it will be converted to one
Example usage:

```javascript
one = Temporal.Instant.fromEpochSeconds(1.0e9);
two = Temporal.Instant.fromEpochSeconds(1.1e9);
one = Temporal.Instant.fromEpochMilliseconds(1.0e12);
two = Temporal.Instant.fromEpochMilliseconds(1.1e12);
one.equals(two); // => false
one.equals(one); // => true
```
Expand Down
8 changes: 4 additions & 4 deletions docs/timezone.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ Example usage:

```javascript
// Getting the UTC offset for a time zone at a particular time
timestamp = Temporal.Instant.fromEpochSeconds(1553993100);
timestamp = Temporal.Instant.fromEpochMilliseconds(1553993100_000);
tz = Temporal.TimeZone.from('Europe/Berlin');
tz.getOffsetNanosecondsFor(timestamp); // => 3600000000000

Expand Down Expand Up @@ -347,7 +347,7 @@ Example usage:

```javascript
// Getting the UTC offset for a time zone at a particular time
timestamp = Temporal.Instant.fromEpochSeconds(1553993100);
timestamp = Temporal.Instant.fromEpochMilliseconds(1553993100_000);
tz = Temporal.TimeZone.from('Europe/Berlin');
tz.getOffsetStringFor(timestamp); // => '+01:00'

Expand Down Expand Up @@ -381,12 +381,12 @@ Example usage:

```javascript
// Converting an exact time to a calendar date / wall-clock time
timestamp = Temporal.Instant.fromEpochSeconds(1553993100);
timestamp = Temporal.Instant.fromEpochMilliseconds(1553993100_000);
tz = Temporal.TimeZone.from('Europe/Berlin');
tz.getPlainDateTimeFor(timestamp); // => 2019-03-31T01:45:00

// What time was the Unix Epoch (timestamp 0) in Bell Labs (Murray Hill, New Jersey, USA)?
epoch = Temporal.Instant.fromEpochSeconds(0);
epoch = Temporal.Instant.fromEpochMilliseconds(0);
tz = Temporal.TimeZone.from('America/New_York');
tz.getPlainDateTimeFor(epoch); // => 1969-12-31T19:00:00
```
Expand Down
26 changes: 14 additions & 12 deletions docs/zoneddatetime.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,40 +358,42 @@ dt.nanosecond; // => 500

> **NOTE**: The possible values for the `month` property start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
### zonedDateTime.**epochSeconds**: number

### zonedDateTime.**epochMilliseconds**: number

### zonedDateTime.**epochMicroseconds**: bigint

### zonedDateTime.**epochNanoseconds**: bigint

The above read-only properties return the integer number of full seconds, milliseconds, microseconds, or nanoseconds between `zonedDateTime` and 00:00 UTC on 1970-01-01, otherwise known as the [UNIX Epoch](https://en.wikipedia.org/wiki/Unix_time).
The above two read-only properties give the integer number of milliseconds or nanoseconds between `zonedDateTime` and 00:00 UTC on 1970-01-01, otherwise known as the [UNIX Epoch](https://en.wikipedia.org/wiki/Unix_time).

These properties are equivalent to `zonedDateTime.toInstant().epochSeconds`, `zonedDateTime.toInstant().epochMilliseconds`, `zonedDateTime.toInstant().epochMicroseconds`, `zonedDateTime.toInstant().epochNanoseconds`, respectively.
Any fractional remainders are truncated towards zero.
These properties are equivalent to `zonedDateTime.toInstant().epochMilliseconds`, and `zonedDateTime.toInstant().epochNanoseconds`, respectively.
Any fractional milliseconds are truncated towards the beginning of time.
The time zone is irrelevant to these properties, because there is only one epoch, not one per time zone.

Note that the `epochSeconds` and `epochMilliseconds` properties are of type `number` (although only integers are returned) while the `epochMicroseconds` and `epochNanoseconds` are of type `bigint`.
Note that the `epochMilliseconds` property is of type `number` (although only integers are returned) while the `epochNanoseconds` property is of type `bigint`.

The `epochMilliseconds` property is the easiest way to construct a legacy `Date` object from a `Temporal.ZonedDateTime` instance.

<!-- prettier-ignore-start -->
```javascript
zdt = Temporal.ZonedDateTime.from('2020-02-01T12:30+09:00[Asia/Tokyo]');
epochSecs = zdt.epochSeconds;
// => 1580527800
epochMs = zdt.epochMilliseconds;
// => 1580527800000
zdt.toInstant().epochMilliseconds;
// => 1580527800000
legacyDate = new Date(epochMs);
// => 2020-02-01T03:30:00.000Z
// (if the system time zone is America/Los_Angeles)
epochMicros = zdt.epochMicroseconds;
// => 1580527800000000n
epochNanos = zdt.epochNanoseconds;
// => 1580527800000000000n

// If you need epoch seconds data:
epochSecs = Math.floor(zdt.epochMillieconds / 1000); // => 1553906700
// => 1580527800

// If you need epoch microseconds data:
// (Note the extra check for correct floor rounding with bigints)
ns = zdt.epochNanoseconds;
epochMicros = ns / 1000n + ((ns % 1000n) < 0n ? -1n : 0n);
// => 1580527800000000n
```
<!-- prettier-ignore-end -->

Expand Down
6 changes: 0 additions & 6 deletions polyfill/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,16 +567,12 @@ export namespace Temporal {
* See https://tc39.es/proposal-temporal/docs/instant.html for more details.
*/
export class Instant {
static fromEpochSeconds(epochSeconds: number): Temporal.Instant;
static fromEpochMilliseconds(epochMilliseconds: number): Temporal.Instant;
static fromEpochMicroseconds(epochMicroseconds: bigint): Temporal.Instant;
static fromEpochNanoseconds(epochNanoseconds: bigint): Temporal.Instant;
static from(item: Temporal.Instant | string): Temporal.Instant;
static compare(one: Temporal.Instant | string, two: Temporal.Instant | string): ComparisonResult;
constructor(epochNanoseconds: bigint);
readonly epochSeconds: number;
readonly epochMilliseconds: number;
readonly epochMicroseconds: bigint;
readonly epochNanoseconds: bigint;
equals(other: Temporal.Instant | string): boolean;
add(
Expand Down Expand Up @@ -1247,9 +1243,7 @@ export namespace Temporal {
readonly inLeapYear: boolean;
readonly offsetNanoseconds: number;
readonly offset: string;
readonly epochSeconds: number;
readonly epochMilliseconds: number;
readonly epochMicroseconds: bigint;
readonly epochNanoseconds: bigint;
equals(other: Temporal.ZonedDateTime | ZonedDateTimeLike | string): boolean;
with(zonedDateTimeLike: ZonedDateTimeLike, options?: ZonedDateTimeAssignmentOptions): Temporal.ZonedDateTime;
Expand Down
22 changes: 0 additions & 22 deletions polyfill/lib/instant.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,11 @@ export class Instant {
}
}

get epochSeconds() {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const value = GetSlot(this, EPOCHNANOSECONDS);
return ES.BigIntFloorDiv(value, 1e9).toJSNumber();
}
get epochMilliseconds() {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const value = bigInt(GetSlot(this, EPOCHNANOSECONDS));
return ES.BigIntFloorDiv(value, 1e6).toJSNumber();
}
get epochMicroseconds() {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
const value = GetSlot(this, EPOCHNANOSECONDS);
return ES.BigIntIfAvailable(ES.BigIntFloorDiv(value, 1e3));
}
get epochNanoseconds() {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
return ES.BigIntIfAvailable(GetSlot(this, EPOCHNANOSECONDS));
Expand Down Expand Up @@ -144,24 +134,12 @@ export class Instant {
return ES.CreateTemporalZonedDateTime(GetSlot(this, EPOCHNANOSECONDS), timeZone, 'iso8601');
}

static fromEpochSeconds(epochSeconds) {
epochSeconds = ES.ToNumber(epochSeconds);
const epochNanoseconds = bigInt(epochSeconds).multiply(1e9);
ES.ValidateEpochNanoseconds(epochNanoseconds);
return new Instant(epochNanoseconds);
}
static fromEpochMilliseconds(epochMilliseconds) {
epochMilliseconds = ES.ToNumber(epochMilliseconds);
const epochNanoseconds = bigInt(epochMilliseconds).multiply(1e6);
ES.ValidateEpochNanoseconds(epochNanoseconds);
return new Instant(epochNanoseconds);
}
static fromEpochMicroseconds(epochMicroseconds) {
epochMicroseconds = ES.ToBigInt(epochMicroseconds);
const epochNanoseconds = epochMicroseconds.multiply(1e3);
ES.ValidateEpochNanoseconds(epochNanoseconds);
return new Instant(epochNanoseconds);
}
static fromEpochNanoseconds(epochNanoseconds) {
epochNanoseconds = ES.ToBigInt(epochNanoseconds);
ES.ValidateEpochNanoseconds(epochNanoseconds);
Expand Down
Loading

0 comments on commit 6fce96c

Please sign in to comment.