summaryrefslogtreecommitdiff
path: root/std/datetime
diff options
context:
space:
mode:
Diffstat (limited to 'std/datetime')
-rw-r--r--std/datetime/README.md188
-rw-r--r--std/datetime/formatter.ts594
-rw-r--r--std/datetime/mod.ts249
-rw-r--r--std/datetime/test.ts393
-rw-r--r--std/datetime/tokenizer.ts76
5 files changed, 0 insertions, 1500 deletions
diff --git a/std/datetime/README.md b/std/datetime/README.md
deleted file mode 100644
index b168cd08b..000000000
--- a/std/datetime/README.md
+++ /dev/null
@@ -1,188 +0,0 @@
-# datetime
-
-Simple helper to help parse date strings into `Date`, with additional functions.
-
-## Usage
-
-The following symbols from
-[unicode LDML](http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table)
-are supported:
-
-- `yyyy` - numeric year.
-- `yy` - 2-digit year.
-- `M` - numeric month.
-- `MM` - 2-digit month.
-- `d` - numeric day.
-- `dd` - 2-digit day.
-
-- `H` - numeric hour (0-23 hours).
-- `HH` - 2-digit hour (00-23 hours).
-- `h` - numeric hour (1-12 hours).
-- `hh` - 2-digit hour (01-12 hours).
-- `m` - numeric minute.
-- `mm` - 2-digit minute.
-- `s` - numeric second.
-- `ss` - 2-digit second.
-- `S` - 1-digit fractionalSecond.
-- `SS` - 2-digit fractionalSecond.
-- `SSS` - 3-digit fractionalSecond.
-
-- `a` - dayPeriod, either `AM` or `PM`.
-
-- `'foo'` - quoted literal.
-- `./-` - unquoted literal.
-
-## Methods
-
-### parse
-
-Takes an input `string` and a `formatString` to parse to a `date`.
-
-```ts
-import { parse } from 'https://deno.land/std@$STD_VERSION/datetime/mod.ts'
-
-parse("20-01-2019", "dd-MM-yyyy") // output : new Date(2019, 0, 20)
-parse("2019-01-20", "yyyy-MM-dd") // output : new Date(2019, 0, 20)
-parse("20.01.2019", "dd.MM.yyyy") // output : new Date(2019, 0, 20)
-parse("01-20-2019 16:34", "MM-dd-yyyy HH:mm") // output : new Date(2019, 0, 20, 16, 34)
-parse("01-20-2019 04:34 PM", "MM-dd-yyyy hh:mm a") // output : new Date(2019, 0, 20, 16, 34)
-parse("16:34 01-20-2019", "HH:mm MM-dd-yyyy") // output : new Date(2019, 0, 20, 16, 34)
-parse("01-20-2019 16:34:23.123", "MM-dd-yyyy HH:mm:ss.SSS") // output : new Date(2019, 0, 20, 16, 34, 23, 123)
-...
-```
-
-### format
-
-Takes an input `date` and a `formatString` to format to a `string`.
-
-```ts
-import { format } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-format(new Date(2019, 0, 20), "dd-MM-yyyy"); // output : "20-01-2019"
-format(new Date(2019, 0, 20), "yyyy-MM-dd"); // output : "2019-01-20"
-format(new Date(2019, 0, 20), "dd.MM.yyyy"); // output : "2019-01-20"
-format(new Date(2019, 0, 20, 16, 34), "MM-dd-yyyy HH:mm"); // output : "01-20-2019 16:34"
-format(new Date(2019, 0, 20, 16, 34), "MM-dd-yyyy hh:mm a"); // output : "01-20-2019 04:34 PM"
-format(new Date(2019, 0, 20, 16, 34), "HH:mm MM-dd-yyyy"); // output : "16:34 01-20-2019"
-format(new Date(2019, 0, 20, 16, 34, 23, 123), "MM-dd-yyyy HH:mm:ss.SSS"); // output : "01-20-2019 16:34:23.123"
-format(new Date(2019, 0, 20), "'today:' yyyy-MM-dd"); // output : "today: 2019-01-20"
-```
-
-### dayOfYear
-
-Returns the number of the day in the year.
-
-```ts
-import { dayOfYear } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-dayOfYear(new Date("2019-03-11T03:24:00")); // output: 70
-```
-
-### weekOfYear
-
-Returns the ISO week number of the provided date (1-53).
-
-```ts
-import { weekOfYear } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-weekOfYear(new Date("2020-12-28T03:24:00")); // Returns 53
-```
-
-### toIMF
-
-Formats the given date to IMF date time format. (Reference:
-https://tools.ietf.org/html/rfc7231#section-7.1.1.1 )
-
-```js
-import { toIMF } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-toIMF(new Date(0)); // => returns "Thu, 01 Jan 1970 00:00:00 GMT"
-```
-
-### isLeap
-
-Returns true if the given date or year (in number) is a leap year. Returns false
-otherwise.
-
-```js
-import { isLeap } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-isLeap(new Date("1970-01-01")); // => returns false
-isLeap(new Date("1972-01-01")); // => returns true
-isLeap(new Date("2000-01-01")); // => returns true
-isLeap(new Date("2100-01-01")); // => returns false
-isLeap(1972); // => returns true
-```
-
-### difference
-
-Returns the difference of the 2 given dates in the given units. If the units are
-omitted, it returns the difference in the all available units.
-
-Available units: "milliseconds", "seconds", "minutes", "hours", "days", "weeks",
-"months", "quarters", "years"
-
-```js
-import { difference } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-const date0 = new Date("2018-05-14");
-const date1 = new Date("2020-05-13");
-
-difference(date0, date1, { units: ["days", "months", "years"] });
-// => returns { days: 730, months: 23, years: 1 }
-
-difference(date0, date1);
-// => returns {
-// milliseconds: 63072000000,
-// seconds: 63072000,
-// minutes: 1051200,
-// hours: 17520,
-// days: 730,
-// weeks: 104,
-// months: 23,
-// quarters: 5,
-// years: 1
-// }
-```
-
-## Constants
-
-### SECOND
-
-```
-import { SECOND } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-console.log(SECOND); // => 1000
-```
-
-### MINUTE
-
-```
-import { MINUTE } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-console.log(MINUTE); // => 60000 (60 * 1000)
-```
-
-### HOUR
-
-```
-import { HOUR } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-console.log(HOUR); // => 3600000 (60 * 60 * 1000)
-```
-
-### DAY
-
-```
-import { DAY } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-console.log(DAY); // => 86400000 (24 * 60 * 60 * 1000)
-```
-
-### WEEK
-
-```
-import { WEEK } from "https://deno.land/std@$STD_VERSION/datetime/mod.ts";
-
-console.log(WEEK); // => 604800000 (7 * 24 * 60 * 60 * 1000)
-```
diff --git a/std/datetime/formatter.ts b/std/datetime/formatter.ts
deleted file mode 100644
index 788de6d00..000000000
--- a/std/datetime/formatter.ts
+++ /dev/null
@@ -1,594 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-import {
- CallbackResult,
- ReceiverResult,
- Rule,
- TestFunction,
- TestResult,
- Tokenizer,
-} from "./tokenizer.ts";
-
-function digits(value: string | number, count = 2): string {
- return String(value).padStart(count, "0");
-}
-
-// as declared as in namespace Intl
-type DateTimeFormatPartTypes =
- | "day"
- | "dayPeriod"
- // | "era"
- | "hour"
- | "literal"
- | "minute"
- | "month"
- | "second"
- | "timeZoneName"
- // | "weekday"
- | "year"
- | "fractionalSecond";
-
-interface DateTimeFormatPart {
- type: DateTimeFormatPartTypes;
- value: string;
-}
-
-type TimeZone = "UTC";
-
-interface Options {
- timeZone?: TimeZone;
-}
-
-function createLiteralTestFunction(value: string): TestFunction {
- return (string: string): TestResult => {
- return string.startsWith(value)
- ? { value, length: value.length }
- : undefined;
- };
-}
-
-function createMatchTestFunction(match: RegExp): TestFunction {
- return (string: string): TestResult => {
- const result = match.exec(string);
- if (result) return { value: result, length: result[0].length };
- };
-}
-
-// according to unicode symbols (http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table)
-const defaultRules = [
- {
- test: createLiteralTestFunction("yyyy"),
- fn: (): CallbackResult => ({ type: "year", value: "numeric" }),
- },
- {
- test: createLiteralTestFunction("yy"),
- fn: (): CallbackResult => ({ type: "year", value: "2-digit" }),
- },
-
- {
- test: createLiteralTestFunction("MM"),
- fn: (): CallbackResult => ({ type: "month", value: "2-digit" }),
- },
- {
- test: createLiteralTestFunction("M"),
- fn: (): CallbackResult => ({ type: "month", value: "numeric" }),
- },
- {
- test: createLiteralTestFunction("dd"),
- fn: (): CallbackResult => ({ type: "day", value: "2-digit" }),
- },
- {
- test: createLiteralTestFunction("d"),
- fn: (): CallbackResult => ({ type: "day", value: "numeric" }),
- },
-
- {
- test: createLiteralTestFunction("HH"),
- fn: (): CallbackResult => ({ type: "hour", value: "2-digit" }),
- },
- {
- test: createLiteralTestFunction("H"),
- fn: (): CallbackResult => ({ type: "hour", value: "numeric" }),
- },
- {
- test: createLiteralTestFunction("hh"),
- fn: (): CallbackResult => ({
- type: "hour",
- value: "2-digit",
- hour12: true,
- }),
- },
- {
- test: createLiteralTestFunction("h"),
- fn: (): CallbackResult => ({
- type: "hour",
- value: "numeric",
- hour12: true,
- }),
- },
- {
- test: createLiteralTestFunction("mm"),
- fn: (): CallbackResult => ({ type: "minute", value: "2-digit" }),
- },
- {
- test: createLiteralTestFunction("m"),
- fn: (): CallbackResult => ({ type: "minute", value: "numeric" }),
- },
- {
- test: createLiteralTestFunction("ss"),
- fn: (): CallbackResult => ({ type: "second", value: "2-digit" }),
- },
- {
- test: createLiteralTestFunction("s"),
- fn: (): CallbackResult => ({ type: "second", value: "numeric" }),
- },
- {
- test: createLiteralTestFunction("SSS"),
- fn: (): CallbackResult => ({ type: "fractionalSecond", value: 3 }),
- },
- {
- test: createLiteralTestFunction("SS"),
- fn: (): CallbackResult => ({ type: "fractionalSecond", value: 2 }),
- },
- {
- test: createLiteralTestFunction("S"),
- fn: (): CallbackResult => ({ type: "fractionalSecond", value: 1 }),
- },
-
- {
- test: createLiteralTestFunction("a"),
- fn: (value: unknown): CallbackResult => ({
- type: "dayPeriod",
- value: value as string,
- }),
- },
-
- // quoted literal
- {
- test: createMatchTestFunction(/^(')(?<value>\\.|[^\']*)\1/),
- fn: (match: unknown): CallbackResult => ({
- type: "literal",
- value: (match as RegExpExecArray).groups!.value as string,
- }),
- },
- // literal
- {
- test: createMatchTestFunction(/^.+?\s*/),
- fn: (match: unknown): CallbackResult => ({
- type: "literal",
- value: (match as RegExpExecArray)[0],
- }),
- },
-];
-
-type FormatPart = {
- type: DateTimeFormatPartTypes;
- value: string | number;
- hour12?: boolean;
-};
-type Format = FormatPart[];
-
-export class DateTimeFormatter {
- #format: Format;
-
- constructor(formatString: string, rules: Rule[] = defaultRules) {
- const tokenizer = new Tokenizer(rules);
- this.#format = tokenizer.tokenize(
- formatString,
- ({ type, value, hour12 }) => {
- const result = {
- type,
- value,
- } as unknown as ReceiverResult;
- if (hour12) result.hour12 = hour12 as boolean;
- return result;
- },
- ) as Format;
- }
-
- format(date: Date, options: Options = {}): string {
- let string = "";
-
- const utc = options.timeZone === "UTC";
-
- for (const token of this.#format) {
- const type = token.type;
-
- switch (type) {
- case "year": {
- const value = utc ? date.getUTCFullYear() : date.getFullYear();
- switch (token.value) {
- case "numeric": {
- string += value;
- break;
- }
- case "2-digit": {
- string += digits(value, 2).slice(-2);
- break;
- }
- default:
- throw Error(
- `FormatterError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "month": {
- const value = (utc ? date.getUTCMonth() : date.getMonth()) + 1;
- switch (token.value) {
- case "numeric": {
- string += value;
- break;
- }
- case "2-digit": {
- string += digits(value, 2);
- break;
- }
- default:
- throw Error(
- `FormatterError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "day": {
- const value = utc ? date.getUTCDate() : date.getDate();
- switch (token.value) {
- case "numeric": {
- string += value;
- break;
- }
- case "2-digit": {
- string += digits(value, 2);
- break;
- }
- default:
- throw Error(
- `FormatterError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "hour": {
- let value = utc ? date.getUTCHours() : date.getHours();
- value -= token.hour12 && date.getHours() > 12 ? 12 : 0;
- switch (token.value) {
- case "numeric": {
- string += value;
- break;
- }
- case "2-digit": {
- string += digits(value, 2);
- break;
- }
- default:
- throw Error(
- `FormatterError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "minute": {
- const value = utc ? date.getUTCMinutes() : date.getMinutes();
- switch (token.value) {
- case "numeric": {
- string += value;
- break;
- }
- case "2-digit": {
- string += digits(value, 2);
- break;
- }
- default:
- throw Error(
- `FormatterError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "second": {
- const value = utc ? date.getUTCSeconds() : date.getSeconds();
- switch (token.value) {
- case "numeric": {
- string += value;
- break;
- }
- case "2-digit": {
- string += digits(value, 2);
- break;
- }
- default:
- throw Error(
- `FormatterError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "fractionalSecond": {
- const value = utc
- ? date.getUTCMilliseconds()
- : date.getMilliseconds();
- string += digits(value, Number(token.value));
- break;
- }
- // FIXME(bartlomieju)
- case "timeZoneName": {
- // string += utc ? "Z" : token.value
- break;
- }
- case "dayPeriod": {
- string += token.value ? (date.getHours() >= 12 ? "PM" : "AM") : "";
- break;
- }
- case "literal": {
- string += token.value;
- break;
- }
-
- default:
- throw Error(`FormatterError: { ${token.type} ${token.value} }`);
- }
- }
-
- return string;
- }
-
- parseToParts(string: string): DateTimeFormatPart[] {
- const parts: DateTimeFormatPart[] = [];
-
- for (const token of this.#format) {
- const type = token.type;
-
- let value = "";
- switch (token.type) {
- case "year": {
- switch (token.value) {
- case "numeric": {
- value = /^\d{1,4}/.exec(string)?.[0] as string;
- break;
- }
- case "2-digit": {
- value = /^\d{1,2}/.exec(string)?.[0] as string;
- break;
- }
- }
- break;
- }
- case "month": {
- switch (token.value) {
- case "numeric": {
- value = /^\d{1,2}/.exec(string)?.[0] as string;
- break;
- }
- case "2-digit": {
- value = /^\d{2}/.exec(string)?.[0] as string;
- break;
- }
- case "narrow": {
- value = /^[a-zA-Z]+/.exec(string)?.[0] as string;
- break;
- }
- case "short": {
- value = /^[a-zA-Z]+/.exec(string)?.[0] as string;
- break;
- }
- case "long": {
- value = /^[a-zA-Z]+/.exec(string)?.[0] as string;
- break;
- }
- default:
- throw Error(
- `ParserError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "day": {
- switch (token.value) {
- case "numeric": {
- value = /^\d{1,2}/.exec(string)?.[0] as string;
- break;
- }
- case "2-digit": {
- value = /^\d{2}/.exec(string)?.[0] as string;
- break;
- }
- default:
- throw Error(
- `ParserError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "hour": {
- switch (token.value) {
- case "numeric": {
- value = /^\d{1,2}/.exec(string)?.[0] as string;
- if (token.hour12 && parseInt(value) > 12) {
- console.error(
- `Trying to parse hour greater than 12. Use 'H' instead of 'h'.`,
- );
- }
- break;
- }
- case "2-digit": {
- value = /^\d{2}/.exec(string)?.[0] as string;
- if (token.hour12 && parseInt(value) > 12) {
- console.error(
- `Trying to parse hour greater than 12. Use 'HH' instead of 'hh'.`,
- );
- }
- break;
- }
- default:
- throw Error(
- `ParserError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "minute": {
- switch (token.value) {
- case "numeric": {
- value = /^\d{1,2}/.exec(string)?.[0] as string;
- break;
- }
- case "2-digit": {
- value = /^\d{2}/.exec(string)?.[0] as string;
- break;
- }
- default:
- throw Error(
- `ParserError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "second": {
- switch (token.value) {
- case "numeric": {
- value = /^\d{1,2}/.exec(string)?.[0] as string;
- break;
- }
- case "2-digit": {
- value = /^\d{2}/.exec(string)?.[0] as string;
- break;
- }
- default:
- throw Error(
- `ParserError: value "${token.value}" is not supported`,
- );
- }
- break;
- }
- case "fractionalSecond": {
- value = new RegExp(`^\\d{${token.value}}`).exec(string)
- ?.[0] as string;
- break;
- }
- case "timeZoneName": {
- value = token.value as string;
- break;
- }
- case "dayPeriod": {
- value = /^(A|P)M/.exec(string)?.[0] as string;
- break;
- }
- case "literal": {
- if (!string.startsWith(token.value as string)) {
- throw Error(
- `Literal "${token.value}" not found "${string.slice(0, 25)}"`,
- );
- }
- value = token.value as string;
- break;
- }
-
- default:
- throw Error(`${token.type} ${token.value}`);
- }
-
- if (!value) {
- throw Error(
- `value not valid for token { ${type} ${value} } ${
- string.slice(
- 0,
- 25,
- )
- }`,
- );
- }
- parts.push({ type, value });
-
- string = string.slice(value.length);
- }
-
- if (string.length) {
- throw Error(
- `datetime string was not fully parsed! ${string.slice(0, 25)}`,
- );
- }
-
- return parts;
- }
-
- /** sort & filter dateTimeFormatPart */
- sortDateTimeFormatPart(parts: DateTimeFormatPart[]): DateTimeFormatPart[] {
- let result: DateTimeFormatPart[] = [];
- const typeArray = [
- "year",
- "month",
- "day",
- "hour",
- "minute",
- "second",
- "fractionalSecond",
- ];
- for (const type of typeArray) {
- const current = parts.findIndex((el) => el.type === type);
- if (current !== -1) {
- result = result.concat(parts.splice(current, 1));
- }
- }
- result = result.concat(parts);
- return result;
- }
-
- partsToDate(parts: DateTimeFormatPart[]): Date {
- const date = new Date();
- const utc = parts.find(
- (part) => part.type === "timeZoneName" && part.value === "UTC",
- );
-
- utc ? date.setUTCHours(0, 0, 0, 0) : date.setHours(0, 0, 0, 0);
- for (const part of parts) {
- switch (part.type) {
- case "year": {
- const value = Number(part.value.padStart(4, "20"));
- utc ? date.setUTCFullYear(value) : date.setFullYear(value);
- break;
- }
- case "month": {
- const value = Number(part.value) - 1;
- utc ? date.setUTCMonth(value) : date.setMonth(value);
- break;
- }
- case "day": {
- const value = Number(part.value);
- utc ? date.setUTCDate(value) : date.setDate(value);
- break;
- }
- case "hour": {
- let value = Number(part.value);
- const dayPeriod = parts.find(
- (part: DateTimeFormatPart) => part.type === "dayPeriod",
- );
- if (dayPeriod?.value === "PM") value += 12;
- utc ? date.setUTCHours(value) : date.setHours(value);
- break;
- }
- case "minute": {
- const value = Number(part.value);
- utc ? date.setUTCMinutes(value) : date.setMinutes(value);
- break;
- }
- case "second": {
- const value = Number(part.value);
- utc ? date.setUTCSeconds(value) : date.setSeconds(value);
- break;
- }
- case "fractionalSecond": {
- const value = Number(part.value);
- utc ? date.setUTCMilliseconds(value) : date.setMilliseconds(value);
- break;
- }
- }
- }
- return date;
- }
-
- parse(string: string): Date {
- const parts = this.parseToParts(string);
- const sortParts = this.sortDateTimeFormatPart(parts);
- return this.partsToDate(sortParts);
- }
-}
diff --git a/std/datetime/mod.ts b/std/datetime/mod.ts
deleted file mode 100644
index 8a3ec7c4f..000000000
--- a/std/datetime/mod.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-
-import { DateTimeFormatter } from "./formatter.ts";
-
-export const SECOND = 1e3;
-export const MINUTE = SECOND * 60;
-export const HOUR = MINUTE * 60;
-export const DAY = HOUR * 24;
-export const WEEK = DAY * 7;
-const DAYS_PER_WEEK = 7;
-
-enum Day {
- Sun,
- Mon,
- Tue,
- Wed,
- Thu,
- Fri,
- Sat,
-}
-
-/**
- * Parse date from string using format string
- * @param dateString Date string
- * @param format Format string
- * @return Parsed date
- */
-export function parse(dateString: string, formatString: string): Date {
- const formatter = new DateTimeFormatter(formatString);
- const parts = formatter.parseToParts(dateString);
- const sortParts = formatter.sortDateTimeFormatPart(parts);
- return formatter.partsToDate(sortParts);
-}
-
-/**
- * Format date using format string
- * @param date Date
- * @param format Format string
- * @return formatted date string
- */
-export function format(date: Date, formatString: string): string {
- const formatter = new DateTimeFormatter(formatString);
- return formatter.format(date);
-}
-
-/**
- * Get number of the day in the year
- * @return Number of the day in year
- */
-export function dayOfYear(date: Date): number {
- // Values from 0 to 99 map to the years 1900 to 1999. All other values are the actual year. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date)
- // Using setFullYear as a workaround
-
- const yearStart = new Date(date);
-
- yearStart.setUTCFullYear(date.getUTCFullYear(), 0, 0);
- const diff = date.getTime() -
- yearStart.getTime() +
- (yearStart.getTimezoneOffset() - date.getTimezoneOffset()) * 60 * 1000;
-
- return Math.floor(diff / DAY);
-}
-/**
- * Get number of the week in the year (ISO-8601)
- * @return Number of the week in year
- */
-export function weekOfYear(date: Date): number {
- const workingDate = new Date(
- Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()),
- );
-
- const day = workingDate.getUTCDay();
-
- const nearestThursday = workingDate.getUTCDate() +
- Day.Thu -
- (day === Day.Sun ? DAYS_PER_WEEK : day);
-
- workingDate.setUTCDate(nearestThursday);
-
- // Get first day of year
- const yearStart = new Date(Date.UTC(workingDate.getUTCFullYear(), 0, 1));
-
- // return the calculated full weeks to nearest Thursday
- return Math.ceil((workingDate.getTime() - yearStart.getTime() + DAY) / WEEK);
-}
-
-/**
- * Parse a date to return a IMF formatted string date
- * RFC: https://tools.ietf.org/html/rfc7231#section-7.1.1.1
- * IMF is the time format to use when generating times in HTTP
- * headers. The time being formatted must be in UTC for Format to
- * generate the correct format.
- * @param date Date to parse
- * @return IMF date formatted string
- */
-export function toIMF(date: Date): string {
- function dtPad(v: string, lPad = 2): string {
- return v.padStart(lPad, "0");
- }
- const d = dtPad(date.getUTCDate().toString());
- const h = dtPad(date.getUTCHours().toString());
- const min = dtPad(date.getUTCMinutes().toString());
- const s = dtPad(date.getUTCSeconds().toString());
- const y = date.getUTCFullYear();
- const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
- const months = [
- "Jan",
- "Feb",
- "Mar",
- "Apr",
- "May",
- "Jun",
- "Jul",
- "Aug",
- "Sep",
- "Oct",
- "Nov",
- "Dec",
- ];
- return `${days[date.getUTCDay()]}, ${d} ${
- months[date.getUTCMonth()]
- } ${y} ${h}:${min}:${s} GMT`;
-}
-
-/**
- * Check given year is a leap year or not.
- * based on : https://docs.microsoft.com/en-us/office/troubleshoot/excel/determine-a-leap-year
- * @param year year in number or Date format
- */
-export function isLeap(year: Date | number): boolean {
- const yearNumber = year instanceof Date ? year.getFullYear() : year;
- return (
- (yearNumber % 4 === 0 && yearNumber % 100 !== 0) || yearNumber % 400 === 0
- );
-}
-
-export type Unit =
- | "milliseconds"
- | "seconds"
- | "minutes"
- | "hours"
- | "days"
- | "weeks"
- | "months"
- | "quarters"
- | "years";
-
-export type DifferenceFormat = Partial<Record<Unit, number>>;
-
-export type DifferenceOptions = {
- units?: Unit[];
-};
-
-/**
- * Calculate difference between two dates.
- * @param from Year to calculate difference
- * @param to Year to calculate difference with
- * @param options Options for determining how to respond
- *
- * example :
- *
- * ```typescript
- * datetime.difference(new Date("2020/1/1"),new Date("2020/2/2"),{ units : ["days","months"] })
- * ```
- */
-export function difference(
- from: Date,
- to: Date,
- options?: DifferenceOptions,
-): DifferenceFormat {
- const uniqueUnits = options?.units ? [...new Set(options?.units)] : [
- "milliseconds",
- "seconds",
- "minutes",
- "hours",
- "days",
- "weeks",
- "months",
- "quarters",
- "years",
- ];
-
- const bigger = Math.max(from.getTime(), to.getTime());
- const smaller = Math.min(from.getTime(), to.getTime());
- const differenceInMs = bigger - smaller;
-
- const differences: DifferenceFormat = {};
-
- for (const uniqueUnit of uniqueUnits) {
- switch (uniqueUnit) {
- case "milliseconds":
- differences.milliseconds = differenceInMs;
- break;
- case "seconds":
- differences.seconds = Math.floor(differenceInMs / SECOND);
- break;
- case "minutes":
- differences.minutes = Math.floor(differenceInMs / MINUTE);
- break;
- case "hours":
- differences.hours = Math.floor(differenceInMs / HOUR);
- break;
- case "days":
- differences.days = Math.floor(differenceInMs / DAY);
- break;
- case "weeks":
- differences.weeks = Math.floor(differenceInMs / WEEK);
- break;
- case "months":
- differences.months = calculateMonthsDifference(bigger, smaller);
- break;
- case "quarters":
- differences.quarters = Math.floor(
- (typeof differences.months !== "undefined" &&
- differences.months / 4) ||
- calculateMonthsDifference(bigger, smaller) / 4,
- );
- break;
- case "years":
- differences.years = Math.floor(
- (typeof differences.months !== "undefined" &&
- differences.months / 12) ||
- calculateMonthsDifference(bigger, smaller) / 12,
- );
- break;
- }
- }
-
- return differences;
-}
-
-function calculateMonthsDifference(bigger: number, smaller: number): number {
- const biggerDate = new Date(bigger);
- const smallerDate = new Date(smaller);
- const yearsDiff = biggerDate.getFullYear() - smallerDate.getFullYear();
- const monthsDiff = biggerDate.getMonth() - smallerDate.getMonth();
- const calendarDifferences = Math.abs(yearsDiff * 12 + monthsDiff);
- const compareResult = biggerDate > smallerDate ? 1 : -1;
- biggerDate.setMonth(
- biggerDate.getMonth() - compareResult * calendarDifferences,
- );
- const isLastMonthNotFull = biggerDate > smallerDate
- ? 1
- : -1 === -compareResult
- ? 1
- : 0;
- const months = compareResult * (calendarDifferences - isLastMonthNotFull);
- return months === 0 ? 0 : months;
-}
diff --git a/std/datetime/test.ts b/std/datetime/test.ts
deleted file mode 100644
index b2614bc00..000000000
--- a/std/datetime/test.ts
+++ /dev/null
@@ -1,393 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals, assertThrows } from "../testing/asserts.ts";
-import * as datetime from "./mod.ts";
-
-Deno.test({
- name: "[std/datetime] parse",
- fn: () => {
- assertEquals(
- datetime.parse("01-03-2019 16:30", "MM-dd-yyyy HH:mm"),
- new Date(2019, 0, 3, 16, 30),
- );
- assertEquals(
- datetime.parse("01.03.2019 16:30", "MM.dd.yyyy HH:mm"),
- new Date(2019, 0, 3, 16, 30),
- );
- assertEquals(
- datetime.parse("01.03.2019 16:30", "MM.dd.yyyy HH:mm"),
- new Date(2019, 0, 3, 16, 30),
- );
- assertEquals(
- datetime.parse("03-01-2019 16:31", "dd-MM-yyyy HH:mm"),
- new Date(2019, 0, 3, 16, 31),
- );
- assertEquals(
- datetime.parse("2019-01-03 16:32", "yyyy-MM-dd HH:mm"),
- new Date(2019, 0, 3, 16, 32),
- );
- assertEquals(
- datetime.parse("16:33 01-03-2019", "HH:mm MM-dd-yyyy"),
- new Date(2019, 0, 3, 16, 33),
- );
- assertEquals(
- datetime.parse("01-03-2019 16:33:23.123", "MM-dd-yyyy HH:mm:ss.SSS"),
- new Date(2019, 0, 3, 16, 33, 23, 123),
- );
- assertEquals(
- datetime.parse("01-03-2019 09:33 PM", "MM-dd-yyyy HH:mm a"),
- new Date(2019, 0, 3, 21, 33),
- );
- assertEquals(
- datetime.parse("16:34 03-01-2019", "HH:mm dd-MM-yyyy"),
- new Date(2019, 0, 3, 16, 34),
- );
- assertEquals(
- datetime.parse("16:35 2019-01-03", "HH:mm yyyy-MM-dd"),
- new Date(2019, 0, 3, 16, 35),
- );
- assertEquals(
- datetime.parse("01-03-2019", "MM-dd-yyyy"),
- new Date(2019, 0, 3),
- );
- assertEquals(
- datetime.parse("03-01-2019", "dd-MM-yyyy"),
- new Date(2019, 0, 3),
- );
- assertEquals(
- datetime.parse("31-10-2019", "dd-MM-yyyy"),
- new Date(2019, 9, 31),
- );
- assertEquals(
- datetime.parse("2019-01-03", "yyyy-MM-dd"),
- new Date(2019, 0, 3),
- );
- },
-});
-
-Deno.test({
- name: "[std/datetime] invalidParseDateTimeFormatThrows",
- fn: () => {
- assertThrows((): void => {
- // deno-lint-ignore no-explicit-any
- (datetime as any).parse("2019-01-01 00:00", "x-y-z");
- }, Error);
- assertThrows((): void => {
- // deno-lint-ignore no-explicit-any
- (datetime as any).parse("2019-01-01", "x-y-z");
- }, Error);
- },
-});
-
-Deno.test({
- name: "[std/datetime] format",
- fn: () => {
- // 00 hours
- assertEquals(
- "01:00:00",
- datetime.format(new Date("2019-01-01T01:00:00"), "HH:mm:ss"),
- );
- assertEquals(
- "13:00:00",
- datetime.format(new Date("2019-01-01T13:00:00"), "HH:mm:ss"),
- );
-
- // 12 hours
- assertEquals(
- "01:00:00",
- datetime.format(new Date("2019-01-01T01:00:00"), "hh:mm:ss"),
- );
- assertEquals(
- "01:00:00",
- datetime.format(new Date("2019-01-01T13:00:00"), "hh:mm:ss"),
- );
-
- // milliseconds
- assertEquals(
- "13:00:00.000",
- datetime.format(new Date("2019-01-01T13:00:00"), "HH:mm:ss.SSS"),
- );
- assertEquals(
- "13:00:00.000",
- datetime.format(new Date("2019-01-01T13:00:00.000"), "HH:mm:ss.SSS"),
- );
- assertEquals(
- "13:00:00.123",
- datetime.format(new Date("2019-01-01T13:00:00.123"), "HH:mm:ss.SSS"),
- );
-
- // day period
- assertEquals(
- "01:00:00 AM",
- datetime.format(new Date("2019-01-01T01:00:00"), "HH:mm:ss a"),
- );
- assertEquals(
- "01:00:00 AM",
- datetime.format(new Date("2019-01-01T01:00:00"), "hh:mm:ss a"),
- );
- assertEquals(
- "01:00:00 PM",
- datetime.format(new Date("2019-01-01T13:00:00"), "hh:mm:ss a"),
- );
- assertEquals(
- "21:00:00 PM",
- datetime.format(new Date("2019-01-01T21:00:00"), "HH:mm:ss a"),
- );
- assertEquals(
- "09:00:00 PM",
- datetime.format(new Date("2019-01-01T21:00:00"), "hh:mm:ss a"),
- );
-
- // quoted literal
- assertEquals(
- datetime.format(new Date(2019, 0, 20), "'today:' yyyy-MM-dd"),
- "today: 2019-01-20",
- );
- },
-});
-
-Deno.test({
- name: "[std/datetime] dayOfYear",
- fn: () => {
- // from https://golang.org/src/time/time_test.go
- // Test YearDay in several different scenarios
- // and corner cases
- // Non-leap-year tests
- assertEquals(datetime.dayOfYear(new Date("2007-01-01T00:00:00.000Z")), 1);
- assertEquals(datetime.dayOfYear(new Date("2007-01-15T00:00:00.000Z")), 15);
- assertEquals(datetime.dayOfYear(new Date("2007-02-01T00:00:00.000Z")), 32);
- assertEquals(datetime.dayOfYear(new Date("2007-02-15T00:00:00.000Z")), 46);
- assertEquals(datetime.dayOfYear(new Date("2007-03-01T00:00:00.000Z")), 60);
- assertEquals(datetime.dayOfYear(new Date("2007-03-15T00:00:00.000Z")), 74);
- assertEquals(datetime.dayOfYear(new Date("2007-04-01T00:00:00.000Z")), 91);
- assertEquals(datetime.dayOfYear(new Date("2007-12-31T00:00:00.000Z")), 365);
-
- // Leap-year tests
- assertEquals(datetime.dayOfYear(new Date("2008-01-01T00:00:00.000Z")), 1);
- assertEquals(datetime.dayOfYear(new Date("2008-01-15T00:00:00.000Z")), 15);
- assertEquals(datetime.dayOfYear(new Date("2008-02-01T00:00:00.000Z")), 32);
- assertEquals(datetime.dayOfYear(new Date("2008-02-15T00:00:00.000Z")), 46);
- assertEquals(datetime.dayOfYear(new Date("2008-03-01T00:00:00.000Z")), 61);
- assertEquals(datetime.dayOfYear(new Date("2008-03-15T00:00:00.000Z")), 75);
- assertEquals(datetime.dayOfYear(new Date("2008-04-01T00:00:00.000Z")), 92);
- assertEquals(datetime.dayOfYear(new Date("2008-12-31T00:00:00.000Z")), 366);
-
- // Looks like leap-year (but isn't) tests
- assertEquals(datetime.dayOfYear(new Date("1900-01-01T00:00:00.000Z")), 1);
- assertEquals(datetime.dayOfYear(new Date("1900-01-15T00:00:00.000Z")), 15);
- assertEquals(datetime.dayOfYear(new Date("1900-02-01T00:00:00.000Z")), 32);
- assertEquals(datetime.dayOfYear(new Date("1900-02-15T00:00:00.000Z")), 46);
- assertEquals(datetime.dayOfYear(new Date("1900-03-01T00:00:00.000Z")), 60);
- assertEquals(datetime.dayOfYear(new Date("1900-03-15T00:00:00.000Z")), 74);
- assertEquals(datetime.dayOfYear(new Date("1900-04-01T00:00:00.000Z")), 91);
- assertEquals(datetime.dayOfYear(new Date("1900-12-31T00:00:00.000Z")), 365);
-
- // Year one tests (non-leap)
- assertEquals(datetime.dayOfYear(new Date("0001-01-01T00:00:00.000Z")), 1);
- assertEquals(datetime.dayOfYear(new Date("0001-01-15T00:00:00.000Z")), 15);
- assertEquals(datetime.dayOfYear(new Date("0001-02-01T00:00:00.000Z")), 32);
- assertEquals(datetime.dayOfYear(new Date("0001-02-15T00:00:00.000Z")), 46);
- assertEquals(datetime.dayOfYear(new Date("0001-03-01T00:00:00.000Z")), 60);
- assertEquals(datetime.dayOfYear(new Date("0001-03-15T00:00:00.000Z")), 74);
- assertEquals(datetime.dayOfYear(new Date("0001-04-01T00:00:00.000Z")), 91);
- assertEquals(datetime.dayOfYear(new Date("0001-12-31T00:00:00.000Z")), 365);
-
- // Year minus one tests (non-leap)
- assertEquals(
- datetime.dayOfYear(new Date("-000001-01-01T00:00:00.000Z")),
- 1,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000001-01-15T00:00:00.000Z")),
- 15,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000001-02-01T00:00:00.000Z")),
- 32,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000001-02-15T00:00:00.000Z")),
- 46,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000001-03-01T00:00:00.000Z")),
- 60,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000001-03-15T00:00:00.000Z")),
- 74,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000001-04-01T00:00:00.000Z")),
- 91,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000001-12-31T00:00:00.000Z")),
- 365,
- );
-
- // 400 BC tests (leap-year)
- assertEquals(
- datetime.dayOfYear(new Date("-000400-01-01T00:00:00.000Z")),
- 1,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000400-01-15T00:00:00.000Z")),
- 15,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000400-02-01T00:00:00.000Z")),
- 32,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000400-02-15T00:00:00.000Z")),
- 46,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000400-03-01T00:00:00.000Z")),
- 61,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000400-03-15T00:00:00.000Z")),
- 75,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000400-04-01T00:00:00.000Z")),
- 92,
- );
- assertEquals(
- datetime.dayOfYear(new Date("-000400-12-31T00:00:00.000Z")),
- 366,
- );
-
- // Special Cases
-
- // Gregorian calendar change (no effect)
- assertEquals(datetime.dayOfYear(new Date("1582-10-04T03:24:00.000Z")), 277);
- assertEquals(datetime.dayOfYear(new Date("1582-10-15T03:24:00.000Z")), 288);
- },
-});
-
-Deno.test({
- name: "[std/datetime] weekOfYear",
- fn: () => {
- assertEquals(datetime.weekOfYear(new Date("2020-01-05T03:00:00.000Z")), 1);
- assertEquals(datetime.weekOfYear(new Date("2020-06-28T03:00:00.000Z")), 26);
-
- // iso weeks year starting sunday
- assertEquals(datetime.weekOfYear(new Date(2012, 0, 1)), 52);
- assertEquals(datetime.weekOfYear(new Date(2012, 0, 2)), 1);
- assertEquals(datetime.weekOfYear(new Date(2012, 0, 8)), 1);
- assertEquals(datetime.weekOfYear(new Date(2012, 0, 9)), 2);
- assertEquals(datetime.weekOfYear(new Date(2012, 0, 15)), 2);
-
- // iso weeks year starting monday
- assertEquals(datetime.weekOfYear(new Date(2007, 0, 1)), 1);
- assertEquals(datetime.weekOfYear(new Date(2007, 0, 7)), 1);
- assertEquals(datetime.weekOfYear(new Date(2007, 0, 8)), 2);
- assertEquals(datetime.weekOfYear(new Date(2007, 0, 14)), 2);
- assertEquals(datetime.weekOfYear(new Date(2007, 0, 15)), 3);
-
- // iso weeks year starting tuesday
- assertEquals(datetime.weekOfYear(new Date(2007, 11, 31)), 1);
- assertEquals(datetime.weekOfYear(new Date(2008, 0, 1)), 1);
- assertEquals(datetime.weekOfYear(new Date(2008, 0, 6)), 1);
- assertEquals(datetime.weekOfYear(new Date(2008, 0, 7)), 2);
- assertEquals(datetime.weekOfYear(new Date(2008, 0, 13)), 2);
- assertEquals(datetime.weekOfYear(new Date(2008, 0, 14)), 3);
-
- // iso weeks year starting wednesday
- assertEquals(datetime.weekOfYear(new Date(2002, 11, 30)), 1);
- assertEquals(datetime.weekOfYear(new Date(2003, 0, 1)), 1);
- assertEquals(datetime.weekOfYear(new Date(2003, 0, 5)), 1);
- assertEquals(datetime.weekOfYear(new Date(2003, 0, 6)), 2);
- assertEquals(datetime.weekOfYear(new Date(2003, 0, 12)), 2);
- assertEquals(datetime.weekOfYear(new Date(2003, 0, 13)), 3);
-
- // iso weeks year starting thursday
- assertEquals(datetime.weekOfYear(new Date(2008, 11, 29)), 1);
- assertEquals(datetime.weekOfYear(new Date(2009, 0, 1)), 1);
- assertEquals(datetime.weekOfYear(new Date(2009, 0, 4)), 1);
- assertEquals(datetime.weekOfYear(new Date(2009, 0, 5)), 2);
- assertEquals(datetime.weekOfYear(new Date(2009, 0, 11)), 2);
- assertEquals(datetime.weekOfYear(new Date(2009, 0, 13)), 3);
-
- // iso weeks year starting friday
- assertEquals(datetime.weekOfYear(new Date(2009, 11, 28)), 53);
- assertEquals(datetime.weekOfYear(new Date(2010, 0, 1)), 53);
- assertEquals(datetime.weekOfYear(new Date(2010, 0, 3)), 53);
- assertEquals(datetime.weekOfYear(new Date(2010, 0, 4)), 1);
- assertEquals(datetime.weekOfYear(new Date(2010, 0, 10)), 1);
- assertEquals(datetime.weekOfYear(new Date(2010, 0, 11)), 2);
-
- // iso weeks year starting saturday
- assertEquals(datetime.weekOfYear(new Date(2010, 11, 27)), 52);
- assertEquals(datetime.weekOfYear(new Date(2011, 0, 1)), 52);
- assertEquals(datetime.weekOfYear(new Date(2011, 0, 2)), 52);
- assertEquals(datetime.weekOfYear(new Date(2011, 0, 3)), 1);
- assertEquals(datetime.weekOfYear(new Date(2011, 0, 9)), 1);
- assertEquals(datetime.weekOfYear(new Date(2011, 0, 10)), 2);
- },
-});
-
-Deno.test({
- name: "[std/datetime] to IMF",
- fn(): void {
- const actual = datetime.toIMF(new Date(Date.UTC(1994, 3, 5, 15, 32)));
- const expected = "Tue, 05 Apr 1994 15:32:00 GMT";
- assertEquals(actual, expected);
- },
-});
-
-Deno.test({
- name: "[std/datetime] to IMF 0",
- fn(): void {
- const actual = datetime.toIMF(new Date(0));
- const expected = "Thu, 01 Jan 1970 00:00:00 GMT";
- assertEquals(actual, expected);
- },
-});
-
-Deno.test({
- name: "[std/datetime] isLeap",
- fn(): void {
- assert(datetime.isLeap(1992));
- assert(datetime.isLeap(2000));
- assert(!datetime.isLeap(2003));
- assert(!datetime.isLeap(2007));
- },
-});
-
-Deno.test({
- name: "[std/datetime] difference",
- fn(): void {
- const denoInit = new Date("2018/5/14");
- const denoReleaseV1 = new Date("2020/5/13");
- let difference = datetime.difference(denoReleaseV1, denoInit, {
- units: ["days", "months", "years"],
- });
- assertEquals(difference.days, 730);
- assertEquals(difference.months, 23);
- assertEquals(difference.years, 1);
-
- const birth = new Date("1998/2/23 10:10:10");
- const old = new Date("1998/2/23 11:11:11");
- difference = datetime.difference(birth, old, {
- units: ["milliseconds", "minutes", "seconds", "hours"],
- });
- assertEquals(difference.milliseconds, 3661000);
- assertEquals(difference.seconds, 3661);
- assertEquals(difference.minutes, 61);
- assertEquals(difference.hours, 1);
- },
-});
-
-Deno.test({
- name: "[std/datetime] constants",
- fn(): void {
- assertEquals(datetime.SECOND, 1e3);
- assertEquals(datetime.MINUTE, datetime.SECOND * 60);
- assertEquals(datetime.HOUR, datetime.MINUTE * 60);
- assertEquals(datetime.DAY, datetime.HOUR * 24);
- assertEquals(datetime.WEEK, datetime.DAY * 7);
- },
-});
diff --git a/std/datetime/tokenizer.ts b/std/datetime/tokenizer.ts
deleted file mode 100644
index 9a9d0daa8..000000000
--- a/std/datetime/tokenizer.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-
-export type Token = {
- type: string;
- value: string | number;
- index: number;
- [key: string]: unknown;
-};
-
-export interface ReceiverResult {
- [name: string]: string | number | unknown;
-}
-export type CallbackResult = {
- type: string;
- value: string | number;
- [key: string]: unknown;
-};
-type CallbackFunction = (value: unknown) => CallbackResult;
-
-export type TestResult = { value: unknown; length: number } | undefined;
-export type TestFunction = (
- string: string,
-) => TestResult | undefined;
-
-export interface Rule {
- test: TestFunction;
- fn: CallbackFunction;
-}
-
-export class Tokenizer {
- rules: Rule[];
-
- constructor(rules: Rule[] = []) {
- this.rules = rules;
- }
-
- addRule(test: TestFunction, fn: CallbackFunction): Tokenizer {
- this.rules.push({ test, fn });
- return this;
- }
-
- tokenize(
- string: string,
- receiver = (token: Token): ReceiverResult => token,
- ): ReceiverResult[] {
- function* generator(rules: Rule[]): IterableIterator<ReceiverResult> {
- let index = 0;
- for (const rule of rules) {
- const result = rule.test(string);
- if (result) {
- const { value, length } = result;
- index += length;
- string = string.slice(length);
- const token = { ...rule.fn(value), index };
- yield receiver(token);
- yield* generator(rules);
- }
- }
- }
- const tokenGenerator = generator(this.rules);
-
- const tokens: ReceiverResult[] = [];
-
- for (const token of tokenGenerator) {
- tokens.push(token);
- }
-
- if (string.length) {
- throw new Error(
- `parser error: string not fully parsed! ${string.slice(0, 25)}`,
- );
- }
-
- return tokens;
- }
-}