├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmrc ├── dist ├── .npmrc ├── datetime.js ├── datetime.min.js ├── package.json └── readme.md ├── gulpfile.js ├── package.json ├── readme.md ├── src ├── DateTime.js ├── calendar │ ├── ACalendarInterval.js │ ├── Day.js │ ├── Hour.js │ ├── Minute.js │ ├── Month.js │ ├── MonthWeeks.js │ ├── Second.js │ ├── Week.js │ ├── Year.js │ └── shared.js ├── constants.js ├── duration │ ├── Duration.js │ └── index.js ├── format.js ├── index.js ├── interval │ ├── Interval.js │ └── index.js ├── locale │ └── en.js ├── parse.js ├── settings.js └── utils.js └── test ├── .eslintrc ├── e2e ├── index.html ├── run.js ├── setup.js └── spec │ └── index.spec.js ├── lib ├── qunit │ ├── qunit.css │ └── qunit.js └── utils │ ├── qunit-extend.js │ └── utils.js ├── readme.md └── unit ├── index.html ├── run.js ├── setup.js └── spec ├── calendar ├── day.spec.js ├── hour.spec.js ├── minute.spec.js ├── month-weeks.spec.js ├── month.spec.js ├── second.spec.js ├── week.spec.js └── year.spec.js ├── clone.spec.js ├── create-instance.spec.js ├── duration └── duration.spec.js ├── format.spec.js ├── getters.spec.js ├── interval └── interval.spec.js ├── invalid.spec.js ├── is.spec.js ├── locale.spec.js ├── locale ├── en.spec.js └── ru.spec.js ├── misc.spec.js ├── now.spec.js ├── parse.spec.js ├── setters.spec.js ├── timezone-default.spec.js ├── timezone-info.spec.js ├── transform-to.spec.js └── transform.spec.js /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = space 3 | indent_size = 2 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | dist/ 3 | node_modules/ 4 | 5 | test/e2e/spec/reference/ 6 | test/e2e/run.js 7 | 8 | test/lib/qunit/ 9 | 10 | Gulpfile.js 11 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": "2015", 4 | "sourceType": "module" 5 | }, 6 | "globals": { 7 | "global": false, 8 | "module": false, 9 | "require": false 10 | }, 11 | "extends": "./node_modules/eslint-config-dshimkin/default.js", 12 | "rules": { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | 4 | npm-debug.log 5 | 6 | coverage/ 7 | node_modules/ 8 | 9 | test/e2e/spec/reference/ 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry = https://registry.npmjs.org/ 2 | -------------------------------------------------------------------------------- /dist/.npmrc: -------------------------------------------------------------------------------- 1 | registry = https://registry.npmjs.org/ 2 | -------------------------------------------------------------------------------- /dist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "datetime2", 3 | "version": "2.0.11", 4 | "description": "Date and time library with iana timezones support", 5 | "author": "Dmitry Shimkin ", 6 | "main": "./datetime.js", 7 | "files": [ 8 | "datetime.js", 9 | "datetime.min.js" 10 | ], 11 | "license": "MIT" 12 | } 13 | -------------------------------------------------------------------------------- /dist/readme.md: -------------------------------------------------------------------------------- 1 | # Datetime 2 | 3 | Date and time library with iana timezones support. 4 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const buble = require('rollup-plugin-buble'); 4 | const exec = require('child_process').exec; 5 | const fs = require('fs'); 6 | const gulp = require('gulp'); 7 | const rename = require('gulp-rename'); 8 | const rollup = require('rollup'); 9 | const sizereport = require('gulp-sizereport'); 10 | const uglify = require('gulp-uglify'); 11 | 12 | const getBanner = ctx => ( 13 | `/** 14 | * datetime2 15 | * Version: ${ctx.version} 16 | * Author: ${ctx.author} 17 | * License: MIT 18 | * https://github.com/datetime-js/datetime 19 | */` 20 | ); 21 | 22 | /** 23 | * ------------------------------------------------------------------------------------- 24 | * Builds datetime 25 | * ------------------------------------------------------------------------------------- 26 | */ 27 | 28 | gulp.task('build', callback => { 29 | const pkg = require('./dist/package.json'); 30 | 31 | const options = { 32 | entry: './src/index.js', 33 | plugins: [ 34 | buble() 35 | ] 36 | }; 37 | 38 | rollup.rollup(options) 39 | .then(bundle => { 40 | const result = bundle.generate({ 41 | banner: getBanner(pkg), 42 | format: 'umd', 43 | moduleName: 'DateTime' 44 | }); 45 | 46 | fs.writeFileSync('./dist/datetime.js', result.code); 47 | 48 | callback(null); 49 | }) 50 | .catch(callback); 51 | }); 52 | 53 | /** 54 | * ------------------------------------------------------------------------------------- 55 | * Creates minified version 56 | * ------------------------------------------------------------------------------------- 57 | */ 58 | 59 | gulp.task('min', () => 60 | gulp.src('./dist/datetime.js') 61 | .pipe(uglify({ 62 | mangle: true, 63 | preserveComments: 'license' 64 | })) 65 | .pipe(rename('datetime.min.js')) 66 | .pipe(gulp.dest('dist/')) 67 | ); 68 | 69 | /** 70 | * ------------------------------------------------------------------------------------- 71 | * Prints report about file size 72 | * ------------------------------------------------------------------------------------- 73 | */ 74 | 75 | gulp.task('report', () => 76 | gulp.src('dist/*.js') 77 | .pipe(sizereport({ 78 | gzip: true, 79 | total: false 80 | })) 81 | ); 82 | 83 | /* 84 | * ------------------------------------------------------------------------------------- 85 | * Creates the target directory 86 | * ------------------------------------------------------------------------------------- 87 | */ 88 | 89 | gulp.task('target', cb => { 90 | exec('mkdir -p ./dist', err => cb(err)); 91 | }); 92 | 93 | /* 94 | * ------------------------------------------------------------------------------------- 95 | * Default task 96 | * ------------------------------------------------------------------------------------- 97 | */ 98 | 99 | gulp.task('default', ['build']); 100 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "datetime2-dev", 3 | "version": "0.0.0", 4 | "description": "Date and time library with iana timezones support", 5 | "devDependencies": { 6 | "chalk": "^1.1.3", 7 | "datetime2-locale-ru": "^2.0.3", 8 | "datetime2-scripts": "^1.0.0", 9 | "datetime2-tzdata": "^1.0.0", 10 | "gulp": "^3.9.0", 11 | "gulp-rename": "^1.2.2", 12 | "gulp-sizereport": "^1.1.3", 13 | "gulp-uglify": "^1.5.3", 14 | "eslint": "^3.5.0", 15 | "eslint-config-dshimkin": "^2.0.0", 16 | "qunit": "^0.9.1", 17 | "rollup": "^0.36.3", 18 | "rollup-plugin-buble": "^0.14.0", 19 | "shelljs": "^0.7.0" 20 | }, 21 | "scripts": { 22 | "build": "gulp target && gulp build", 23 | "cov": "node ./test/unit/run.js --coverage", 24 | "e2e": "node ./test/e2e/run.js", 25 | "gen": "./node_modules/.bin/generate-test-cases --tzdata node_modules/datetime2-tzdata/tzdata/ --output ./test/e2e/spec/reference/", 26 | "lint": "eslint ./", 27 | "min": "gulp min", 28 | "report": "gulp report", 29 | "unit": "node ./test/unit/run.js" 30 | }, 31 | "license": "MIT" 32 | } 33 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # DateTime 2 | 3 | DateTime is a lightweight and performant date and time library with iana timezones support. 4 | 5 | 6 | ## Motivation 7 | 8 | DateTime does not use native Date object. Instead it uses pre-parsed 9 | [IANA Time Zone Database](https://www.iana.org/time-zones) 10 | directly from JavaScript. That allows to keep it predictable, reliable, and future proof on any platform. 11 | 12 | 13 | ## Key features 14 | 15 | - Supports [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) standard, including intervals and durations 16 | - Supports timezones and DST 17 | - Works in any browser on any platform independently from the native Date 18 | - [Very fast](#performance) 19 | - Small size – only 10 KB compressed 20 | - No dependencies 21 | - 99% covered with unit tests 22 | 23 | 24 | 25 | ## API documentation 26 | 27 | Coming soon. 28 | 29 | 30 | 31 | ## Performance 32 | 33 | DateTime is much faster than any other library with timezones support: 34 | 35 | ``` 36 | Create a new instance with an array 37 | ================================================================== 38 | DateTime × 782,154 ops/sec 39 | MomentJS × 260,938 ops/sec 40 | MomentJS + Timezones × 49,593 ops/sec 41 | Fastest is DateTime 42 | 43 | Create a new instance with a string 44 | ================================================================== 45 | DateTime × 383,795 ops/sec 46 | MomentJS × 34,681 ops/sec 47 | MomentJS with timezones × 20,491 ops/sec 48 | js-joda with timezones × 20,153 ops/sec 49 | Fastest is DateTime 50 | 51 | Create a new instance with a string and format 52 | ================================================================== 53 | DateTime × 504,000 ops/sec 54 | MomentJS × 38,349 ops/sec 55 | MomentJS + Timezones × 21,643 ops/sec 56 | Fastest is DateTime 57 | ``` 58 | 59 | Check [datetime-benchmark](https://github.com/datetime-js/datetime-benchmark) for details. 60 | 61 | 62 | ## Licence 63 | 64 | MIT 65 | -------------------------------------------------------------------------------- /src/calendar/ACalendarInterval.js: -------------------------------------------------------------------------------- 1 | import DateTime from '../DateTime'; 2 | import Interval from '../interval/Interval'; 3 | import { extend, inherit } from '../utils'; 4 | 5 | /** 6 | * @param {DateTime} dt 7 | * @class 8 | * @abstract 9 | */ 10 | export default function ACalendarInterval (dt) { 11 | } 12 | 13 | inherit(Interval, ACalendarInterval); 14 | 15 | /** 16 | * ---------------------------------------------------------------------------------------- 17 | * Private methods 18 | * ---------------------------------------------------------------------------------------- 19 | */ 20 | 21 | /** 22 | * @param {DateTime|string|number|Array.} dt 23 | * @param {string} [timezoneName] 24 | * @returns {DateTime} 25 | * @inner 26 | */ 27 | export function parseArgument (dt, timezoneName) { 28 | const argsCount = arguments.length; 29 | 30 | if (argsCount === 0) { 31 | return new DateTime(); 32 | } 33 | 34 | if (argsCount === 1) { 35 | return new DateTime(dt); 36 | } 37 | 38 | return new DateTime(dt, timezoneName); 39 | } 40 | 41 | /** 42 | * ---------------------------------------------------------------------------------------- 43 | * Public methods 44 | * ---------------------------------------------------------------------------------------- 45 | */ 46 | 47 | /** 48 | * @returns {Day} 49 | * @public 50 | */ 51 | function toNext () { 52 | const dt = this._end.clone(); 53 | dt.add(1); 54 | return new this.constructor(dt); 55 | } 56 | 57 | /** 58 | * @returns {Day} 59 | * @public 60 | */ 61 | function toPrev () { 62 | const dt = this._start.clone(); 63 | dt.setTime(dt - 1); 64 | return new this.constructor(dt); 65 | } 66 | 67 | /** 68 | * ---------------------------------------------------------------------------------------- 69 | * Expose API 70 | * ---------------------------------------------------------------------------------------- 71 | */ 72 | 73 | extend(ACalendarInterval.prototype, { 74 | toNext, 75 | toPrev 76 | }); 77 | -------------------------------------------------------------------------------- /src/calendar/Day.js: -------------------------------------------------------------------------------- 1 | import { updateValidity } from '../interval/Interval'; 2 | 3 | import ACalendarInterval, { parseArgument } from './ACalendarInterval'; 4 | import Hour from './Hour'; 5 | 6 | import { 7 | getDayOfMonth, 8 | getDayOfWeek, 9 | getISODayOfWeek, 10 | getMonth, 11 | getYear, 12 | isToday, 13 | isWeekend, 14 | toDayISOString 15 | } from './shared'; 16 | 17 | import { 18 | toMonth, 19 | toMonthWeeks, 20 | toWeek, 21 | toYear 22 | } from './shared'; 23 | 24 | import { extend, inherit } from '../utils'; 25 | 26 | /** 27 | * @class Day 28 | */ 29 | export default function Day () { 30 | init.apply(this, arguments); 31 | } 32 | 33 | inherit(ACalendarInterval, Day); 34 | 35 | /** 36 | * @param {DateTime|String|Number|Array} dt 37 | * @param {String} [timezoneName] 38 | */ 39 | function init (dt, timezoneName) { 40 | const start = parseArgument.apply(null, arguments); 41 | start.setStartOfDay(); 42 | 43 | const end = start.clone(); 44 | end.setDayOfMonth(start.getDayOfMonth() + 1); 45 | 46 | this._start = start; 47 | this._end = end; 48 | 49 | updateValidity(this); 50 | } 51 | 52 | /** 53 | * @returns {Array.} 54 | * @public 55 | */ 56 | function toHours () { 57 | const hours = []; 58 | const dayEnd = this.toEnd(); 59 | 60 | let hour = new Hour(this.toStart()); 61 | 62 | // Maximum possible number of hours in a day 63 | let count = 48; 64 | 65 | while (count--) { 66 | if (hour.toEnd() > dayEnd) { 67 | break; 68 | } 69 | 70 | hours.push(hour); 71 | hour = hour.toNext(); 72 | } 73 | 74 | return hours; 75 | } 76 | 77 | extend(Day.prototype, { 78 | getDayOfMonth, 79 | getDayOfWeek, 80 | getISODayOfWeek, 81 | getMonth, 82 | getYear, 83 | isToday, 84 | isWeekend, 85 | toDayISOString, 86 | toHours, 87 | toMonth, 88 | toMonthWeeks, 89 | toWeek, 90 | toYear 91 | }); 92 | -------------------------------------------------------------------------------- /src/calendar/Hour.js: -------------------------------------------------------------------------------- 1 | import { updateValidity } from '../interval/Interval'; 2 | 3 | import ACalendarInterval, { parseArgument } from './ACalendarInterval'; 4 | import Minute from './Minute'; 5 | 6 | import { 7 | getDayOfMonth, 8 | getDayOfWeek, 9 | getHour, 10 | getISODayOfWeek, 11 | getMonth, 12 | getYear 13 | } from './shared'; 14 | 15 | import { extend, inherit } from '../utils'; 16 | import { HOUR_MS } from '../constants'; 17 | 18 | export default function Hour () { 19 | init.apply(this, arguments); 20 | } 21 | 22 | inherit(ACalendarInterval, Hour); 23 | 24 | /** 25 | * @param {DateTime|string|number|Array.} dt 26 | * @param {string} [timezoneName] 27 | */ 28 | function init (dt, timezoneName) { 29 | const start = parseArgument.apply(null, arguments); 30 | start.setStartOfHour(); 31 | 32 | const end = start.clone(); 33 | end.add(HOUR_MS); 34 | 35 | this._start = start; 36 | this._end = end; 37 | 38 | updateValidity(this); 39 | } 40 | 41 | /** 42 | * @returns {Array.} 43 | * @public 44 | */ 45 | function toMinutes () { 46 | const hourEnd = this.toEnd(); 47 | const minutes = []; 48 | 49 | let minute = new Minute(this.toStart()); 50 | 51 | // Number of minutes in a hour 52 | let count = 60; 53 | 54 | while (count--) { 55 | minutes.push(minute); 56 | minute = minute.toNext(); 57 | } 58 | 59 | return minutes; 60 | } 61 | 62 | extend(Hour.prototype, { 63 | getDayOfMonth, 64 | getDayOfWeek, 65 | getHour, 66 | getISODayOfWeek, 67 | getMonth, 68 | getYear, 69 | toMinutes 70 | }); 71 | -------------------------------------------------------------------------------- /src/calendar/Minute.js: -------------------------------------------------------------------------------- 1 | import { updateValidity } from '../interval/Interval'; 2 | 3 | import ACalendarInterval, { parseArgument } from './ACalendarInterval'; 4 | import Second from './Second'; 5 | 6 | import { 7 | getDayOfMonth, 8 | getDayOfWeek, 9 | getHour, 10 | getISODayOfWeek, 11 | getMinute, 12 | getMonth, 13 | getYear 14 | } from './shared'; 15 | 16 | import { extend, inherit } from '../utils'; 17 | 18 | export default function Minute () { 19 | init.apply(this, arguments); 20 | } 21 | 22 | inherit(ACalendarInterval, Minute); 23 | 24 | /** 25 | * @param {DateTime|string|number|Array.} dt 26 | * @param {String} [timezoneName] 27 | */ 28 | function init (dt, timezoneName) { 29 | const start = parseArgument.apply(null, arguments); 30 | start.setStartOfMinute(); 31 | 32 | const end = start.clone(); 33 | end.setMinute(start.getMinute() + 1); 34 | 35 | this._start = start; 36 | this._end = end; 37 | 38 | updateValidity(this); 39 | } 40 | 41 | /** 42 | * @returns {Array.} 43 | * @public 44 | */ 45 | function toSeconds () { 46 | const minuteEnd = this.toEnd(); 47 | const seconds = []; 48 | 49 | let second = new Second(this.toStart()); 50 | 51 | // Number of seconds in a minute 52 | let count = 60; 53 | 54 | while (count--) { 55 | seconds.push(second); 56 | second = second.toNext(); 57 | } 58 | 59 | return seconds; 60 | } 61 | 62 | extend(Minute.prototype, { 63 | getDayOfMonth, 64 | getDayOfWeek, 65 | getHour, 66 | getISODayOfWeek, 67 | getMinute, 68 | getMonth, 69 | getYear, 70 | toSeconds 71 | }); 72 | -------------------------------------------------------------------------------- /src/calendar/Month.js: -------------------------------------------------------------------------------- 1 | import { updateValidity } from '../interval/Interval'; 2 | 3 | import ACalendarInterval, { parseArgument } from './ACalendarInterval'; 4 | import Day from './Day'; 5 | 6 | import { getMonth, getYear } from './shared'; 7 | import { extend, inherit } from '../utils'; 8 | 9 | /** 10 | * @name Month 11 | * @class 12 | */ 13 | export default function Month () { 14 | init.apply(this, arguments); 15 | } 16 | 17 | inherit(ACalendarInterval, Month); 18 | 19 | /** 20 | * @param {DateTime|string|number|Array.} dt 21 | * @param {string} [timezoneName] 22 | */ 23 | function init (dt, timezoneName) { 24 | const start = parseArgument.apply(null, arguments); 25 | start.setStartOfMonth(); 26 | 27 | const end = start.clone(); 28 | end.setMonth(start.getMonth() + 1); 29 | 30 | this._start = start; 31 | this._end = end; 32 | 33 | updateValidity(this); 34 | } 35 | 36 | /** 37 | * @returns {Array} 38 | * @public 39 | */ 40 | function toDays () { 41 | const days = []; 42 | const dtend = this.toEnd(); 43 | 44 | let day = new Day(this.toStart()); 45 | let count = 31; 46 | 47 | while (count--) { 48 | if (day.toEnd() > dtend) { 49 | break; 50 | } 51 | 52 | days.push(day); 53 | day = day.toNext(); 54 | } 55 | 56 | return days; 57 | } 58 | 59 | extend(Month.prototype, { 60 | getMonth, 61 | getYear, 62 | toDays 63 | }); 64 | -------------------------------------------------------------------------------- /src/calendar/MonthWeeks.js: -------------------------------------------------------------------------------- 1 | import { updateValidity } from '../interval/Interval'; 2 | 3 | import ACalendarInterval, { parseArgument } from './ACalendarInterval'; 4 | import Week from './Week'; 5 | 6 | import { extend, inherit } from '../utils'; 7 | 8 | /** 9 | * @name MonthWeeks 10 | * @class 11 | */ 12 | export default function MonthWeeks () { 13 | init.apply(this, arguments); 14 | } 15 | 16 | inherit(ACalendarInterval, MonthWeeks); 17 | 18 | /** 19 | * @param {DateTime|string|number|Array.} dt 20 | * @param {string} [timezoneName] 21 | */ 22 | function init (dt, timezoneName) { 23 | const start = parseArgument.apply(null, arguments); 24 | const end = start.clone(); 25 | 26 | start 27 | .setStartOfMonth() 28 | .setStartOfWeek(); 29 | 30 | end 31 | .setEndOfMonth() 32 | .setEndOfWeek() 33 | .add(1); 34 | 35 | this._start = start; 36 | this._end = end; 37 | 38 | updateValidity(this); 39 | } 40 | 41 | /** 42 | * @returns {Array} 43 | * @public 44 | */ 45 | function toWeeks () { 46 | const weeks = []; 47 | const dtend = this.toEnd(); 48 | 49 | let week = new Week(this.toStart()); 50 | let count = 6; 51 | 52 | while (count--) { 53 | if (week.toEnd() > dtend) { 54 | break; 55 | } 56 | 57 | weeks.push(week); 58 | week = week.toNext(); 59 | } 60 | 61 | return weeks; 62 | } 63 | 64 | extend(MonthWeeks.prototype, { toWeeks }); 65 | -------------------------------------------------------------------------------- /src/calendar/Second.js: -------------------------------------------------------------------------------- 1 | import { updateValidity } from '../interval/Interval'; 2 | 3 | import ACalendarInterval, { parseArgument } from './ACalendarInterval'; 4 | 5 | import { 6 | getDayOfMonth, 7 | getDayOfWeek, 8 | getHour, 9 | getISODayOfWeek, 10 | getMinute, 11 | getMonth, 12 | getSecond, 13 | getYear 14 | } from './shared'; 15 | 16 | import { extend, inherit } from '../utils'; 17 | 18 | export default function Second () { 19 | init.apply(this, arguments); 20 | } 21 | 22 | inherit(ACalendarInterval, Second); 23 | 24 | /** 25 | * @param {DateTime|string|number|Array.} dt 26 | * @param {string} [timezoneName] 27 | */ 28 | function init (dt, timezoneName) { 29 | const start = parseArgument.apply(null, arguments); 30 | start.setStartOfSecond(); 31 | 32 | const end = start.clone(); 33 | end.setSecond(start.getSecond() + 1); 34 | 35 | this._start = start; 36 | this._end = end; 37 | 38 | updateValidity(this); 39 | } 40 | 41 | extend(Second.prototype, { 42 | getDayOfMonth, 43 | getDayOfWeek, 44 | getHour, 45 | getISODayOfWeek, 46 | getMinute, 47 | getMonth, 48 | getSecond, 49 | getYear 50 | }); 51 | -------------------------------------------------------------------------------- /src/calendar/Week.js: -------------------------------------------------------------------------------- 1 | import { updateValidity } from '../interval/Interval'; 2 | 3 | import ACalendarInterval, { parseArgument } from './ACalendarInterval'; 4 | import Day from './Day'; 5 | 6 | import { getWeekOfYear } from './shared'; 7 | import { extend, inherit } from '../utils'; 8 | 9 | /** 10 | * @name Week 11 | * @class 12 | */ 13 | export default function Week () { 14 | init.apply(this, arguments); 15 | } 16 | 17 | inherit(ACalendarInterval, Week); 18 | 19 | /** 20 | * @param {DateTime|string|number|Array.} dt 21 | * @param {string} [timezoneName] 22 | */ 23 | function init (dt, timezoneName) { 24 | const start = parseArgument.apply(null, arguments); 25 | start.setStartOfWeek(); 26 | 27 | const end = start.clone(); 28 | end.setDayOfMonth(start.getDayOfMonth() + 7); 29 | 30 | this._start = start; 31 | this._end = end; 32 | 33 | updateValidity(this); 34 | } 35 | 36 | /** 37 | * @returns {Array} 38 | * @public 39 | */ 40 | function toDays () { 41 | const days = []; 42 | 43 | let day = new Day(this.toStart()); 44 | let count = 7; 45 | 46 | while (count--) { 47 | days.push(day); 48 | day = day.toNext(); 49 | } 50 | 51 | return days; 52 | } 53 | 54 | extend(Week.prototype, { 55 | getWeekOfYear, 56 | toDays 57 | }); 58 | -------------------------------------------------------------------------------- /src/calendar/Year.js: -------------------------------------------------------------------------------- 1 | import { updateValidity } from '../interval/Interval'; 2 | import ACalendarInterval, { parseArgument } from './ACalendarInterval'; 3 | import Month from './Month'; 4 | import MonthWeeks from './MonthWeeks'; 5 | import { getYear, isLeap } from './shared'; 6 | import { extend, inherit } from '../utils'; 7 | 8 | /** 9 | * @name Year 10 | * @class 11 | */ 12 | export default function Year () { 13 | init.apply(this, arguments); 14 | } 15 | 16 | inherit(ACalendarInterval, Year); 17 | 18 | /** 19 | * @param {DateTime|string|number|Array.} dt 20 | * @param {string} [timezoneName] 21 | */ 22 | function init (dt, timezoneName) { 23 | const start = parseArgument.apply(null, arguments); 24 | start.setStartOfYear(); 25 | 26 | const end = start.clone(); 27 | end.setYear(start.getYear() + 1); 28 | 29 | this._start = start; 30 | this._end = end; 31 | 32 | updateValidity(this); 33 | } 34 | 35 | /** 36 | * @returns {Array.} 37 | * @public 38 | */ 39 | function toMonths () { 40 | let count = 12; 41 | const months = []; 42 | 43 | let month = new Month(this.toStart()); 44 | 45 | while (count--) { 46 | months.push(month); 47 | month = month.toNext(); 48 | } 49 | 50 | return months; 51 | } 52 | 53 | /** 54 | * @returns {Array.} 55 | * @public 56 | */ 57 | function toMonthWeeks () { 58 | let count = 12; 59 | const monthWeeksList = []; 60 | 61 | let monthWeeks = new MonthWeeks(this.toStart()); 62 | 63 | while (count--) { 64 | monthWeeksList.push(monthWeeks); 65 | monthWeeks = monthWeeks.toNext(); 66 | } 67 | 68 | return monthWeeksList; 69 | } 70 | 71 | extend(Year.prototype, { 72 | getYear, 73 | isLeap, 74 | toMonths, 75 | toMonthWeeks 76 | }); 77 | -------------------------------------------------------------------------------- /src/calendar/shared.js: -------------------------------------------------------------------------------- 1 | import Day from './Day'; 2 | import Month from './Month'; 3 | import MonthWeeks from './MonthWeeks'; 4 | import Week from './Week'; 5 | import Year from './Year'; 6 | 7 | import { isDateTimeToday, isDateTimeWeekend, isLeapYear } from '../utils'; 8 | import { getLocaleData } from '../settings'; 9 | 10 | const ISO_DAY_FORMAT = 'YYYY-MM-DD'; 11 | 12 | /** 13 | * @returns {number} 14 | */ 15 | export function getDayOfWeek () { 16 | return this._start.getDayOfWeek(); 17 | } 18 | 19 | /** 20 | * @returns {number} 21 | */ 22 | export function getDayOfMonth () { 23 | return this._start.getDayOfMonth(); 24 | } 25 | 26 | /** 27 | * @returns {number} 28 | */ 29 | export function getHour () { 30 | return this._start.getHour(); 31 | } 32 | 33 | /** 34 | * @returns {number} 35 | */ 36 | export function getISODayOfWeek () { 37 | return this._start.getISODayOfWeek(); 38 | } 39 | 40 | /** 41 | * @returns {number} 42 | */ 43 | export function getMinute () { 44 | return this._start.getMinute(); 45 | } 46 | 47 | /** 48 | * @returns {number} 49 | */ 50 | export function getMonth () { 51 | return this._start.getMonth(); 52 | } 53 | 54 | /** 55 | * @returns {number} 56 | */ 57 | export function getSecond () { 58 | return this._start.getSecond(); 59 | } 60 | 61 | /** 62 | * @returns {number} 63 | */ 64 | export function getWeekOfYear () { 65 | return this._start.getWeekOfYear(); 66 | } 67 | 68 | /** 69 | * @returns {number} 70 | */ 71 | export function getYear () { 72 | return this._start.getYear(); 73 | } 74 | 75 | /** 76 | * @returns {boolean} 77 | */ 78 | export function isToday () { 79 | return isDateTimeToday(this._start); 80 | } 81 | 82 | /** 83 | * @returns {boolean} 84 | */ 85 | export function isLeap () { 86 | return isLeapYear(this._start.getYear()); 87 | } 88 | 89 | /** 90 | * @returns {boolean} 91 | */ 92 | export function isWeekend () { 93 | return isDateTimeWeekend(this._start, getLocaleData()); 94 | } 95 | 96 | /** 97 | * @returns {Day} 98 | */ 99 | export function toDay () { 100 | return new Day(this._start); 101 | } 102 | 103 | /** 104 | * @returns {Day} 105 | */ 106 | export function toDayISOString () { 107 | return this._start.format(ISO_DAY_FORMAT); 108 | } 109 | 110 | /** 111 | * @returns {Month} 112 | */ 113 | export function toMonth () { 114 | return new Month(this._start); 115 | } 116 | 117 | /** 118 | * @returns {MonthWeeks} 119 | */ 120 | export function toMonthWeeks () { 121 | return new MonthWeeks(this._start); 122 | } 123 | 124 | /** 125 | * @returns {Week} 126 | */ 127 | export function toWeek () { 128 | return new Week(this._start); 129 | } 130 | 131 | /** 132 | * @returns {Year} 133 | */ 134 | export function toYear () { 135 | return new Year(this._start); 136 | } 137 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ------------------------------------------------------------------------------------- 3 | * Constants 4 | * ------------------------------------------------------------------------------------- 5 | */ 6 | 7 | /** {number} Year of the Unix Epoch beginning */ 8 | export const EPOCH_START = 1970; 9 | 10 | /** {number} */ 11 | export const SECOND_MS = 1000; 12 | 13 | /** {number} */ 14 | export const MINUTE_MS = 60 * SECOND_MS; 15 | 16 | /** {number} */ 17 | export const HOUR_MS = 60 * MINUTE_MS; 18 | 19 | /** {number} */ 20 | export const DAY_MS = 24 * HOUR_MS; 21 | 22 | /** {number} */ 23 | export const YEAR_MS = 365 * DAY_MS; 24 | 25 | /** {number} */ 26 | export const LEAP_YEAR_MS = 366 * DAY_MS; 27 | 28 | /** {number} */ 29 | export const MONTH_MS = 30.5 * DAY_MS; 30 | 31 | /** {Array.} */ 32 | export const MONTH_POINTS = [0]; 33 | 34 | /** {Array.} */ 35 | export const LEAP_MONTH_POINTS = [0]; 36 | 37 | /** {string} */ 38 | export const FORMAT_RFC822 = 'ddd MMM DD YYYY HH:mm:ss ZZ (zz)'; 39 | 40 | /** {string} */ 41 | export const UTC_TIMEZONE = 'UTC'; 42 | 43 | /** {number} */ 44 | export const MIN_TIMESTAMP_VALUE = -9007199254740992; 45 | 46 | /** {number} */ 47 | export const MAX_TIMESTAMP_VALUE = 9007199254740992; 48 | 49 | /** {string} */ 50 | export const E_INVALID_ARGUMENT = 'E_INVALID_ARGUMENT'; 51 | 52 | /** {string} */ 53 | export const E_INVALID_ATTRIBUTE = 'E_INVALID_ATTRIBUTE'; 54 | 55 | /** {string} */ 56 | export const E_INVALID_INTERVAL_ORDER = 'E_INVALID_INTERVAL_ORDER'; 57 | 58 | /** {string} */ 59 | export const E_INVALID_SETTER_ATTRIBUTE = 'E_INVALID_SETTER_ATTRIBUTE'; 60 | 61 | /** {string} */ 62 | export const E_INVALID_TZDATA = 'E_INVALID_TZDATA'; 63 | 64 | /** {string} */ 65 | export const E_INVALID_TIMEZONE = 'E_INVALID_TIMEZONE'; 66 | 67 | /** {string} */ 68 | export const E_PARSE_FORMAT = 'E_PARSE_FORMAT'; 69 | 70 | /** {string} */ 71 | export const E_PARSE_ISO = 'E_PARSE_ISO'; 72 | 73 | /** {string} */ 74 | export const E_RANGE = 'E_RANGE'; 75 | 76 | /** {Object} */ 77 | export const message = { 78 | [E_INVALID_ARGUMENT]: arg => `${String(arg)} is not a valid argument. Argument must be a string, ` + 79 | 'or a number, or an array, or another instance of DateTime', 80 | 81 | [E_INVALID_ATTRIBUTE]: () => 'At least one of the given date attributes is not a valid number', 82 | 83 | [E_INVALID_INTERVAL_ORDER]: () => 'Interval end cannot be earlier than interval start', 84 | 85 | [E_INVALID_SETTER_ATTRIBUTE]: arg => `${String(arg)} is not a valid argument. Argument must be a number.`, 86 | 87 | [E_INVALID_TIMEZONE]: timezoneName => `Cannot find tzdata for timezone ${String(timezoneName)} – fallback to UTC`, 88 | 89 | [E_INVALID_TZDATA]: tzdata => `${String(tzdata)} is not a valid tzdata`, 90 | 91 | [E_PARSE_FORMAT]: (dateStr, format) => `String "${dateStr}" does not match to the given "${format}" format`, 92 | 93 | [E_PARSE_ISO]: dateStr => `String "${dateStr}" is not a valid ISO-8601 date`, 94 | 95 | [E_RANGE]: arg => `Timestamp ${arg} is too big. It must be in a range of ` + 96 | '-9,007,199,254,740,992 to 9,007,199,254,740,992' 97 | }; 98 | 99 | let value; 100 | let prev; 101 | let next; 102 | 103 | const monthDaysCount = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; 104 | 105 | for (let month = 1; month < 12; month++) { 106 | prev = MONTH_POINTS[month - 1]; 107 | value = monthDaysCount[month - 1] * DAY_MS; 108 | next = prev + value; 109 | MONTH_POINTS.push(next); 110 | if (month === 1) { 111 | LEAP_MONTH_POINTS.push(next); 112 | } else { 113 | LEAP_MONTH_POINTS.push(next + DAY_MS); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/duration/Duration.js: -------------------------------------------------------------------------------- 1 | import { extend, isString, toInteger } from '../utils'; 2 | 3 | const RE_ISO8601 = /^(-)?P(?:([0-9]+)Y)?(?:([0-9]+)M)?(?:([0-9]+)D)?(T(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+)S)?)?$/; 4 | 5 | /** 6 | * @param {Duration} duration 7 | * @param {string} str 8 | * @inner 9 | */ 10 | function createFromString (duration, str) { 11 | if (!isParsableAsDuration(str)) { 12 | setInvalid(duration); 13 | return; 14 | } 15 | 16 | const matches = str.match(RE_ISO8601); 17 | const sign = Number((matches[1] || '').toString() + '1'); 18 | 19 | duration.sign = sign; 20 | 21 | duration.years = toInteger(matches[2]) * sign; 22 | duration.months = toInteger(matches[3]) * sign; 23 | duration.days = toInteger(matches[4]) * sign; 24 | duration.hours = toInteger(matches[6]) * sign; 25 | duration.minutes = toInteger(matches[7]) * sign; 26 | duration.seconds = toInteger(matches[8]) * sign; 27 | 28 | duration.invalid = false; 29 | } 30 | 31 | /** 32 | * @param {Duration} duration 33 | * @inner 34 | */ 35 | function createFromUndefined (duration) { 36 | duration.sign = 1; 37 | 38 | duration.years = 0; 39 | duration.months = 0; 40 | duration.days = 0; 41 | duration.hours = 0; 42 | duration.minutes = 0; 43 | duration.seconds = 0; 44 | 45 | duration.invalid = false; 46 | } 47 | 48 | /** 49 | * @param {string} str 50 | * @returns {boolean} 51 | */ 52 | function isParsableAsDuration (str) { 53 | const matches = String(str).match(RE_ISO8601); 54 | return Boolean(matches && matches[0]); 55 | } 56 | 57 | /** 58 | * @param {Duration} duration 59 | * @inner 60 | */ 61 | function setInvalid (duration) { 62 | duration.invalid = true; 63 | } 64 | 65 | /** 66 | * @private 67 | */ 68 | function getDateStr (duration) { 69 | let dateStr = ''; 70 | 71 | if (duration.getYears() !== 0) { 72 | dateStr = dateStr + `${Math.abs(duration.getYears())}Y`; 73 | } 74 | 75 | if (duration.getMonths() !== 0) { 76 | dateStr = dateStr + `${Math.abs(duration.getMonths())}M`; 77 | } 78 | 79 | if (duration.getDays() !== 0) { 80 | dateStr = dateStr + `${Math.abs(duration.getDays())}D`; 81 | } 82 | 83 | return dateStr; 84 | } 85 | 86 | /** 87 | * @private 88 | */ 89 | function getTimeStr (duration) { 90 | let timeStr = ''; 91 | 92 | if (duration.getHours() !== 0) { 93 | timeStr = timeStr + `${Math.abs(duration.getHours())}H`; 94 | } 95 | 96 | if (duration.getMinutes() !== 0) { 97 | timeStr = timeStr + `${Math.abs(duration.getMinutes())}M`; 98 | } 99 | 100 | if (duration.getSeconds() !== 0) { 101 | timeStr = timeStr + `${Math.abs(duration.getSeconds())}S`; 102 | } 103 | 104 | return timeStr; 105 | } 106 | 107 | /** 108 | * @returns {boolean} 109 | * @public 110 | */ 111 | function isInvalid () { 112 | return Boolean(this.invalid); 113 | } 114 | 115 | /** 116 | * @returns {string} 117 | * @public 118 | */ 119 | function toISOString () { 120 | return this.toString(); 121 | } 122 | 123 | /** 124 | * @returns {string} 125 | * @public 126 | */ 127 | function toString () { 128 | const timeStr = getTimeStr(this); 129 | let str = `P${getDateStr(this)}`; 130 | 131 | if (timeStr) { 132 | str = str + `T${timeStr}`; 133 | } 134 | 135 | const sign = this.sign === -1 ? '-' : ''; 136 | 137 | return `${sign}${str}`; 138 | } 139 | 140 | /** 141 | * @name Duration 142 | * @param {string} arg 143 | * @class 144 | */ 145 | function Duration (arg) { 146 | const duration = this; 147 | 148 | duration.invalid = false; 149 | 150 | if (arg === void 0) { 151 | createFromUndefined(duration); 152 | return; 153 | } 154 | 155 | if (isString(arg)) { 156 | createFromString(duration, arg); 157 | return; 158 | } 159 | 160 | setInvalid(duration); 161 | } 162 | 163 | /** 164 | * @returns {number} 165 | * @public 166 | */ 167 | function getYears () { 168 | return this.years; 169 | } 170 | 171 | /** 172 | * @returns {number} 173 | * @public 174 | */ 175 | function getMonths () { 176 | return this.months; 177 | } 178 | 179 | /** 180 | * @returns {number} 181 | * @public 182 | */ 183 | function getDays () { 184 | return this.days; 185 | } 186 | 187 | /** 188 | * @returns {number} 189 | * @public 190 | */ 191 | function getHours () { 192 | return this.hours; 193 | } 194 | 195 | /** 196 | * @returns {number} 197 | * @public 198 | */ 199 | function getMinutes () { 200 | return this.minutes; 201 | } 202 | 203 | /** 204 | * @returns {number} 205 | * @public 206 | */ 207 | function getSeconds () { 208 | return this.seconds; 209 | } 210 | 211 | extend(Duration, { isParsableAsDuration }); 212 | 213 | extend(Duration.prototype, { 214 | getDays, 215 | getHours, 216 | getMinutes, 217 | getMonths, 218 | getSeconds, 219 | getYears, 220 | isInvalid, 221 | toISOString, 222 | toString 223 | }); 224 | 225 | export default Duration; 226 | -------------------------------------------------------------------------------- /src/duration/index.js: -------------------------------------------------------------------------------- 1 | import Duration from './Duration'; 2 | 3 | export default Duration; 4 | -------------------------------------------------------------------------------- /src/format.js: -------------------------------------------------------------------------------- 1 | import { 2 | getLocaleData, 3 | getLocaleDataFor 4 | } from './settings'; 5 | 6 | import { 7 | calcDayOfWeek, 8 | leftPad 9 | } from './utils'; 10 | 11 | /* 12 | * ------------------------------------------------------------------------------------- 13 | * Format 14 | * ------------------------------------------------------------------------------------- 15 | */ 16 | 17 | /* eslint max-len: ["off"] */ 18 | const REG = /YYYY|YY|Y|Qo|Q|MMMM|MMM|MM|Mo|M|DDDD|DDDo|DDD|DD|Do|D|dddd|ddd|dd|do|d|E|e|HH|H|hh|h|kk|k|A|a|mm|m|ss|s|SSS|SS|S|WW|Wo|W|ww|wo|w|GGGG|gggg|X|x|ZZ|Z|zz|z/g; 19 | 20 | /** 21 | * @inner 22 | */ 23 | function getOffsetString (offset, separator) { 24 | const sign = offset <= 0 ? '+' : '-'; 25 | 26 | offset = Math.abs(offset); 27 | 28 | let minutes = offset / 60000 | 0; 29 | const hours = minutes / 60 | 0; 30 | 31 | minutes = minutes - hours * 60; 32 | 33 | return sign + leftPad(hours, 2) + separator + leftPad(minutes, 2); 34 | } 35 | 36 | /** 37 | * @param {Number} num 38 | * @param {Number} [kind] 39 | * @inner 40 | */ 41 | function getOrdinalSuffix (num, kind) { 42 | const locale = getLocaleData(); 43 | const remainder10 = num % 10; 44 | const remainder100 = num % 100; 45 | const suffixes = kind === 2 ? locale.ordinal2 : locale.ordinal; 46 | 47 | if (remainder10 === 1 && remainder100 !== 11) { 48 | return suffixes[0]; 49 | } 50 | 51 | if (remainder10 === 2 && remainder100 !== 12) { 52 | return suffixes[1]; 53 | } 54 | 55 | if (remainder10 === 3 && remainder100 !== 13) { 56 | return suffixes[2]; 57 | } 58 | 59 | return suffixes[3]; 60 | } 61 | 62 | /** 63 | * @param {DateTime} dt 64 | * @param {String} format 65 | * @param {String} localeName 66 | * @inner 67 | */ 68 | export function formatDate (dt, format, localeName) { 69 | const locale = localeName 70 | ? getLocaleDataFor(localeName) 71 | : getLocaleData(); 72 | 73 | if (!format) { 74 | format = 'YYYY-MM-DDTHH:mm:ssZ'; 75 | } 76 | 77 | const useUTC = false; 78 | 79 | const year = dt.date[0]; 80 | const yearStr = String(year); 81 | 82 | const month = dt.date[1]; 83 | const dayOfMonth = dt.date[2]; 84 | const hour = dt.date[3]; 85 | const minute = dt.date[4]; 86 | const second = dt.date[5]; 87 | const millisecond = dt.date[6]; 88 | 89 | let prevToken; 90 | let suffix; 91 | 92 | format = format.replace(REG, function replaceToken (token) { 93 | let str = ''; 94 | 95 | switch (token) { 96 | case 'YYYY': { 97 | str = leftPad(year, token.length); 98 | break; 99 | } 100 | 101 | case 'YY': { 102 | const shortYearStr = yearStr.slice(2, 4); 103 | str = leftPad(shortYearStr, token.length); 104 | break; 105 | } 106 | 107 | case 'Y': { 108 | str = yearStr; 109 | break; 110 | } 111 | 112 | case 'Qo': { 113 | const quarter = dt.getQuarter(); 114 | str = quarter + getOrdinalSuffix(quarter); 115 | break; 116 | } 117 | 118 | case 'Q': { 119 | str = String(dt.getQuarter()); 120 | break; 121 | } 122 | 123 | case 'MMMM': { 124 | let caseIdx = 0; 125 | 126 | if (prevToken === 'D' || prevToken === 'DD' || prevToken === 'Do') { 127 | caseIdx = 1; 128 | } 129 | 130 | str = locale.monthNames[month - 1][caseIdx]; 131 | break; 132 | } 133 | 134 | case 'MMM': { 135 | str = locale.monthNamesShort[month - 1]; 136 | break; 137 | } 138 | 139 | case 'M': 140 | case 'MM': { 141 | str = leftPad(month, token.length); 142 | break; 143 | } 144 | 145 | case 'Mo': { 146 | str = month + getOrdinalSuffix(month); 147 | break; 148 | } 149 | 150 | case 'WW': { 151 | str = leftPad(dt.getISOWeekOfYear(), 2); 152 | break; 153 | } 154 | 155 | case 'Wo': { 156 | const isoWeekOfYear = dt.getISOWeekOfYear(); 157 | str = isoWeekOfYear + getOrdinalSuffix(isoWeekOfYear, 2); 158 | break; 159 | } 160 | 161 | case 'W': { 162 | str = String(dt.getISOWeekOfYear()); 163 | break; 164 | } 165 | 166 | case 'ww': { 167 | str = leftPad(dt.getWeekOfYear(), 2); 168 | break; 169 | } 170 | 171 | case 'wo': { 172 | const weekOfYear = dt.getWeekOfYear(); 173 | str = weekOfYear + getOrdinalSuffix(weekOfYear, 2); 174 | break; 175 | } 176 | 177 | case 'w': { 178 | str = String(dt.getWeekOfYear()); 179 | break; 180 | } 181 | 182 | case 'GGGG': { 183 | str = String(dt.getISOWeekYear()); 184 | break; 185 | } 186 | 187 | case 'gggg': { 188 | str = String(dt.getWeekYear()); 189 | break; 190 | } 191 | 192 | case 'DDDD': { 193 | str = leftPad(dt.getDayOfYear(), 3); 194 | break; 195 | } 196 | 197 | case 'DDDo': { 198 | const dayOfYear = dt.getDayOfYear(); 199 | suffix = getOrdinalSuffix(dayOfYear); 200 | str = dayOfYear + suffix; 201 | break; 202 | } 203 | 204 | case 'DDD': { 205 | str = String(dt.getDayOfYear()); 206 | break; 207 | } 208 | 209 | case 'DD': { 210 | if (dayOfMonth < 10) { 211 | str = `0${dayOfMonth}`; 212 | } else { 213 | str = dayOfMonth; 214 | } 215 | break; 216 | } 217 | 218 | case 'Do': { 219 | str = dayOfMonth + getOrdinalSuffix(dayOfMonth); 220 | break; 221 | } 222 | 223 | case 'D': { 224 | str = String(dayOfMonth); 225 | break; 226 | } 227 | 228 | case 'dddd': { 229 | str = locale.weekDayNames[calcDayOfWeek(dt, useUTC, locale.mondayFirst)]; 230 | break; 231 | } 232 | 233 | case 'ddd': { 234 | str = locale.weekDayNamesShort[calcDayOfWeek(dt, useUTC, locale.mondayFirst)]; 235 | break; 236 | } 237 | 238 | case 'dd': { 239 | str = locale.weekDayNamesShortest[calcDayOfWeek(dt, useUTC, locale.mondayFirst)]; 240 | break; 241 | } 242 | 243 | case 'do': { 244 | const dayOfWeek = calcDayOfWeek(dt, useUTC, locale.mondayFirst); 245 | suffix = getOrdinalSuffix(dayOfWeek); 246 | str = dayOfWeek + suffix; 247 | break; 248 | } 249 | 250 | case 'd': { 251 | str = String(calcDayOfWeek(dt, useUTC, locale.mondayFirst)); 252 | break; 253 | } 254 | 255 | case 'e': { 256 | str = String(dt.getDayOfWeek()); 257 | break; 258 | } 259 | 260 | case 'E': { 261 | str = String(dt.getISODayOfWeek()); 262 | break; 263 | } 264 | 265 | case 'H': 266 | case 'HH': { 267 | str = leftPad(hour, token.length); 268 | break; 269 | } 270 | 271 | case 'h': 272 | case 'hh': { 273 | const meridiemHour = dt.getHourMeridiem(); 274 | str = leftPad(meridiemHour, token.length); 275 | break; 276 | } 277 | 278 | case 'k': 279 | case 'kk': { 280 | const hour24 = hour === 0 ? 24 : hour; 281 | str = leftPad(hour24, token.length); 282 | break; 283 | } 284 | 285 | case 'A': { 286 | str = dt.getMeridiem().toUpperCase(); 287 | break; 288 | } 289 | 290 | case 'a': { 291 | str = dt.getMeridiem(); 292 | break; 293 | } 294 | 295 | case 'm': 296 | case 'mm': { 297 | str = leftPad(minute, token.length); 298 | break; 299 | } 300 | 301 | case 's': 302 | case 'ss': { 303 | str = leftPad(second, token.length); 304 | break; 305 | } 306 | 307 | case 'S': 308 | case 'SS': 309 | case 'SSS': { 310 | str = leftPad(millisecond, token.length); 311 | break; 312 | } 313 | 314 | case 'X': { 315 | str = String(dt.getUnixTimestamp()); 316 | break; 317 | } 318 | 319 | case 'x': { 320 | str = String(dt.valueOf()); 321 | break; 322 | } 323 | 324 | case 'ZZ': { 325 | str = getOffsetString(dt.getTimezoneOffset(), ''); 326 | break; 327 | } 328 | 329 | case 'Z': { 330 | str = getOffsetString(dt.getTimezoneOffset(), ':'); 331 | break; 332 | } 333 | 334 | case 'z': 335 | case 'zz': { 336 | str = dt.getTimezoneAbbr(); 337 | break; 338 | } 339 | } 340 | 341 | prevToken = token; 342 | 343 | return str; 344 | }); 345 | 346 | return format; 347 | } 348 | 349 | /** 350 | * @param {DateTime} dt 351 | * @returns {String} 352 | * @inner 353 | */ 354 | export function formatDateISO (dt) { 355 | const yearStr = String(dt.getUTCYear()); 356 | const monthStr = leftPad(dt.getUTCMonth(), 2); 357 | const dayOfMonthStr = leftPad(dt.getUTCDayOfMonth(), 2); 358 | const hourStr = leftPad(dt.getUTCHour(), 2); 359 | const minuteStr = leftPad(dt.getUTCMinute(), 2); 360 | const secondStr = leftPad(dt.getUTCSecond(), 2); 361 | const millisecondStr = leftPad(dt.getUTCMillisecond(), 3); 362 | 363 | return `${yearStr}-${monthStr}-${dayOfMonthStr}T${hourStr}:${minuteStr}:${secondStr}.${millisecondStr}Z`; 364 | } 365 | 366 | /** 367 | * @param {DateTime} dt 368 | * @returns {String} 369 | * @inner 370 | */ 371 | export function formatDateUTC (dt) { 372 | const locale = getLocaleDataFor('en'); 373 | 374 | const yearStr = String(dt.getUTCYear()); 375 | 376 | const month = dt.getUTCMonth(); 377 | const monthStr = locale.monthNamesShort[month - 1]; 378 | 379 | const dayOfMonthStr = leftPad(dt.getUTCDayOfMonth(), 2); 380 | const dayOfWeek = calcDayOfWeek(dt, false, locale.mondayFirst); 381 | const dayOfWeekStr = locale.weekDayNamesShort[dayOfWeek]; 382 | 383 | const hourStr = leftPad(dt.getUTCHour(), 2); 384 | const minuteStr = leftPad(dt.getUTCMinute(), 2); 385 | const secondStr = leftPad(dt.getUTCSecond(), 2); 386 | 387 | return `${dayOfWeekStr}, ${dayOfMonthStr} ${monthStr} ${yearStr} ${hourStr}:${minuteStr}:${secondStr} GMT`; 388 | } 389 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import DateTime from './DateTime'; 2 | import { extend } from './utils'; 3 | 4 | import localeEn from './locale/en'; 5 | 6 | import Duration from './duration/Duration'; 7 | import Interval from './interval/Interval'; 8 | 9 | import Second from './calendar/Second'; 10 | import Minute from './calendar/Minute'; 11 | import Hour from './calendar/Hour'; 12 | import Day from './calendar/Day'; 13 | import Week from './calendar/Week'; 14 | import Month from './calendar/Month'; 15 | import MonthWeeks from './calendar/MonthWeeks'; 16 | import Year from './calendar/Year'; 17 | 18 | extend(DateTime, { 19 | Day, 20 | Duration, 21 | Hour, 22 | Interval, 23 | Minute, 24 | Month, 25 | MonthWeeks, 26 | Second, 27 | Week, 28 | Year 29 | }); 30 | 31 | DateTime.defineLocale('en', localeEn); 32 | 33 | export default DateTime; 34 | -------------------------------------------------------------------------------- /src/interval/Interval.js: -------------------------------------------------------------------------------- 1 | import DateTime from '../DateTime'; 2 | 3 | import { E_INVALID_INTERVAL_ORDER, message } from '../constants'; 4 | 5 | import { 6 | extend, 7 | isDateTime, 8 | isInterval, 9 | isFiniteNumber, 10 | warn 11 | } from '../utils'; 12 | 13 | function parseArg (arg) { 14 | return new DateTime(arg); 15 | } 16 | 17 | /** 18 | * @name Interval 19 | * @param {DateTime|string|number} start 20 | * @param {DateTime|string|number} end 21 | * @class 22 | */ 23 | function Interval (start, end) { 24 | const dtstart = parseArg(start); 25 | const dtend = parseArg(end); 26 | 27 | this._start = dtstart; 28 | this._end = dtend; 29 | 30 | updateValidity(this); 31 | } 32 | 33 | /** 34 | * ---------------------------------------------------------------------------------------- 35 | * Static inner functions 36 | * ---------------------------------------------------------------------------------------- 37 | */ 38 | 39 | /** 40 | * @param {Interval} interval 41 | * @inner 42 | */ 43 | export function updateValidity (interval) { 44 | const start = interval._start; 45 | const end = interval._end; 46 | 47 | interval._invalid = false; 48 | 49 | if (start.isInvalid() || end.isInvalid()) { 50 | interval._invalid = true; 51 | return; 52 | } 53 | 54 | if (start > end) { 55 | warn(message[E_INVALID_INTERVAL_ORDER]()); 56 | interval._invalid = true; 57 | } 58 | } 59 | 60 | /** 61 | * ---------------------------------------------------------------------------------------- 62 | * Private methods 63 | * ---------------------------------------------------------------------------------------- 64 | */ 65 | 66 | function isStartOfDay (dt) { 67 | return dt.isEqual(dt.toStartOfDay()); 68 | } 69 | 70 | /** 71 | * ---------------------------------------------------------------------------------------- 72 | * Public methods 73 | * ---------------------------------------------------------------------------------------- 74 | */ 75 | 76 | /** 77 | * @param {string} formatStr 78 | * @returns {string} 79 | * @public 80 | */ 81 | function format (formatStr) { 82 | if (this.isInvalid()) { 83 | return 'Invalid interval'; 84 | } 85 | return `${this._start.format(formatStr)} – ${this._end.format(formatStr)}`; 86 | } 87 | 88 | /** 89 | * @returns {number} 90 | * @public 91 | */ 92 | function getDuration () { 93 | return this._end - this._start; 94 | } 95 | 96 | /** 97 | * @param {Interval} interval 98 | * @returns {Interval|Null} 99 | * @public 100 | */ 101 | function getIntersection (interval) { 102 | const start = this._start > interval._start ? this._start : interval._start; 103 | const end = this._end < interval._end ? this._end : interval._end; 104 | 105 | if (start >= end) { 106 | return null; 107 | } 108 | 109 | return new Interval(start, end); 110 | } 111 | 112 | /** 113 | * @param {Interval|DateTime|number} arg 114 | * @returns {boolean} 115 | * @public 116 | */ 117 | function includes (arg) { 118 | if (isInterval(arg)) { 119 | return includesInterval(this, arg); 120 | } 121 | 122 | if (isDateTime(arg)) { 123 | return includesDateTime(this, arg); 124 | } 125 | 126 | if (isFiniteNumber(arg)) { 127 | return includesTimestamp(this, arg); 128 | } 129 | 130 | throw new Error('Wrong argument'); 131 | } 132 | 133 | /** 134 | * @returns {boolean} 135 | */ 136 | function includesInterval (intervalA, intervalB) { 137 | return intervalA._start <= intervalB._start && intervalA._end >= intervalB._end; 138 | } 139 | 140 | /** 141 | * @param {Interval} interval 142 | * @param {DateTime} dt 143 | * @returns {boolean} 144 | */ 145 | function includesDateTime (interval, dt) { 146 | return interval._start <= dt && interval._end >= dt; 147 | } 148 | 149 | /** 150 | * @param {Interval} interval 151 | * @param {number} timestamp 152 | * @returns {boolean} 153 | */ 154 | function includesTimestamp (interval, timestamp) { 155 | return interval._start <= timestamp && interval._end >= timestamp; 156 | } 157 | 158 | /** 159 | * @param {Interval} interval 160 | * @returns {boolean} 161 | * @public 162 | */ 163 | function intersects (interval) { 164 | const start = this._start > interval._start ? this._start : interval._start; 165 | const end = this._end < interval._end ? this._end : interval._end; 166 | 167 | return end > start; 168 | } 169 | 170 | /** 171 | * @public 172 | */ 173 | function isEqual (interval) { 174 | return this._start.isEqual(interval.toStart()) && 175 | this._end.isEqual(interval.toEnd()); 176 | } 177 | 178 | /** 179 | * @returns {boolean} 180 | * @public 181 | */ 182 | function isInvalid () { 183 | return this._invalid; 184 | } 185 | 186 | /** 187 | * @returns {boolean} 188 | * @public 189 | */ 190 | function isValid () { 191 | return !this._invalid; 192 | } 193 | 194 | /** 195 | * @public 196 | */ 197 | function shift () { 198 | // @TBI 199 | } 200 | 201 | /** 202 | * @returns {DateTime} 203 | * @public 204 | */ 205 | function toEnd () { 206 | return this._end.clone(); 207 | } 208 | 209 | /** 210 | * @public 211 | */ 212 | function toIntersectingDays () { 213 | const intervalStart = this._start; 214 | const intervalEnd = this._end; 215 | 216 | const days = []; 217 | 218 | let day = intervalStart.toDay(); 219 | 220 | do { 221 | days.push(day); 222 | day = day.toNext(); 223 | } while (day.toStart() < intervalEnd); 224 | 225 | return days; 226 | } 227 | 228 | /** 229 | * @public 230 | */ 231 | function toIncludingDays () { 232 | const intervalStart = this._start; 233 | const intervalEnd = this._end; 234 | 235 | const days = []; 236 | 237 | let day = intervalStart.toDay(); 238 | if (!isStartOfDay(intervalStart)) { 239 | day = day.toNext(); 240 | } 241 | 242 | while (day.toEnd() <= intervalEnd) { 243 | days.push(day); 244 | day = day.toNext(); 245 | } 246 | 247 | return days; 248 | } 249 | 250 | /** 251 | * @returns {string} 252 | * @public 253 | */ 254 | function toISOString () { 255 | if (this.isInvalid()) { 256 | return 'Invalid interval'; 257 | } 258 | return `${this._start.toISOString()} – ${this._end.toISOString()}`; 259 | } 260 | 261 | /** 262 | * @public 263 | */ 264 | function toJSON () { 265 | return this.toString(); 266 | } 267 | 268 | /** 269 | * @public 270 | */ 271 | function toLocaleString () { 272 | if (this.isInvalid()) { 273 | return 'Invalid interval'; 274 | } 275 | return `${this._start.toLocaleString()} – ${this._end.toLocaleString()}`; 276 | } 277 | 278 | /** 279 | * @public 280 | */ 281 | function toPeriod () { 282 | // @TBI 283 | } 284 | 285 | /** 286 | * @returns {DateTime} 287 | * @public 288 | */ 289 | function toStart () { 290 | return this._start.clone(); 291 | } 292 | 293 | /** 294 | * @returns {string} 295 | * @public 296 | */ 297 | function toString () { 298 | if (this.isInvalid()) { 299 | return 'Invalid interval'; 300 | } 301 | return `${this._start.toString()} – ${this._end.toString()}`; 302 | } 303 | 304 | /** 305 | * @returns {string} 306 | * @public 307 | */ 308 | function toUTCString () { 309 | if (this.isInvalid()) { 310 | return 'Invalid interval'; 311 | } 312 | return `${this._start.toUTCString()} – ${this._end.toUTCString()}`; 313 | } 314 | 315 | /** 316 | * @param {Interval} interval 317 | * @returns {Interval} 318 | * @public 319 | */ 320 | function union (interval) { 321 | const start = this._start < interval._start ? this._start : interval._start; 322 | const end = this._end > interval._end ? this._end : interval._end; 323 | 324 | return new Interval(start, end); 325 | } 326 | 327 | /** 328 | * @public 329 | */ 330 | function valueOf () { 331 | return this.getDuration(); 332 | } 333 | 334 | /** 335 | * ---------------------------------------------------------------------------------------- 336 | * Expose API 337 | * ---------------------------------------------------------------------------------------- 338 | */ 339 | 340 | extend(Interval.prototype, { 341 | format, 342 | getDuration, 343 | getIntersection, 344 | includes, 345 | intersects, 346 | isEqual, 347 | isInvalid, 348 | isValid, 349 | shift, 350 | toEnd, 351 | toIncludingDays, 352 | toIntersectingDays, 353 | toISOString, 354 | toJSON, 355 | toLocaleString, 356 | toPeriod, 357 | toStart, 358 | toString, 359 | toUTCString, 360 | union, 361 | valueOf 362 | }); 363 | 364 | export default Interval; 365 | -------------------------------------------------------------------------------- /src/interval/index.js: -------------------------------------------------------------------------------- 1 | import Interval from './Interval'; 2 | 3 | export default Interval; 4 | -------------------------------------------------------------------------------- /src/locale/en.js: -------------------------------------------------------------------------------- 1 | export default { 2 | formats: [ 3 | 'M/D/YYYY, h:mm:ss A' 4 | ], 5 | mondayFirst: false, 6 | monthNames: [ 7 | ['January', 'January'], 8 | ['February', 'February'], 9 | ['March', 'March'], 10 | ['April', 'April'], 11 | ['May', 'May'], 12 | ['June', 'June'], 13 | ['July', 'July'], 14 | ['August', 'August'], 15 | ['September', 'September'], 16 | ['October', 'October'], 17 | ['November', 'November'], 18 | ['December', 'December'] 19 | ], 20 | monthNamesShort: [ 21 | 'Jan', 22 | 'Feb', 23 | 'Mar', 24 | 'Apr', 25 | 'May', 26 | 'Jun', 27 | 'Jul', 28 | 'Aug', 29 | 'Sep', 30 | 'Oct', 31 | 'Nov', 32 | 'Dec' 33 | ], 34 | ordinal: ['st', 'nd', 'rd', 'th'], 35 | ordinal2: ['st', 'nd', 'rd', 'th'], 36 | weekDayNames: [ 37 | 'Sunday', 38 | 'Monday', 39 | 'Tuesday', 40 | 'Wednesday', 41 | 'Thursday', 42 | 'Friday', 43 | 'Saturday' 44 | ], 45 | weekDayNamesShort: [ 46 | 'Sun', 47 | 'Mon', 48 | 'Tue', 49 | 'Wed', 50 | 'Thu', 51 | 'Fri', 52 | 'Sat' 53 | ], 54 | weekDayNamesShortest: [ 55 | 'Su', 56 | 'Mo', 57 | 'Tu', 58 | 'We', 59 | 'Th', 60 | 'Fr', 61 | 'Sa' 62 | ] 63 | }; 64 | -------------------------------------------------------------------------------- /src/parse.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ------------------------------------------------------------------------------------- 3 | * Parse 4 | * ------------------------------------------------------------------------------------- 5 | */ 6 | 7 | import { now, trim } from './utils'; 8 | 9 | const isoRe = [ 10 | /^([^\s]{4,})[T]?$/, 11 | /^([^\s]{4,})[T\s]([^\s]{2,12}?)(Z|[+-][^\s]{2,5})?$/ 12 | ]; 13 | 14 | const dateRe = [ 15 | /^(\d{4})$/, // YYYY 16 | /^(\d{4})-(\d{1,2})$/, // YYYY-MM, YYYY-M 17 | /^(\d{4})(\d{2})(\d{2})$/, // YYYYMMDD, YYYY-M-D 18 | /^([-+]?\d{4,6})-(\d{1,2})-(\d{1,2})$/ // (+-)YYYY-MM-DD, (+-)YYYYYY-MM-DD 19 | ]; 20 | 21 | const timeRe = [ 22 | /^(\d{2})$/, // HH 23 | /^(\d{2})(\d{2})$/, // HHmm 24 | /^(\d{2}):(\d{2})$/, // HH:mm 25 | /^(\d{2})(\d{2})(\d{2})([.,](\d{3}))?$/, // HHmmss, HHmmss.SSS, HHmmss,SSS 26 | /^(\d{2}):(\d{2}):(\d{2})([.,](\d{3}))?$/ // HH:mm:ss, HH:mm:ss.SSS, HH:mm:ss,SSS 27 | ]; 28 | 29 | const offsetRe = [ 30 | /^([+-])(\d{2})$/, // +-HH 31 | /^([+-])(\d{2})(:)?(\d{2})$/ // +-HH:mm, +-HHmm 32 | ]; 33 | 34 | const formatCache = {}; 35 | 36 | const parseTokens = [ 37 | { 38 | kind: 'year', 39 | pattern: '\\d{1,4}', 40 | reg: /YYYY/g, 41 | token: 'YYYY' 42 | }, 43 | { 44 | kind: 'year', 45 | pattern: '\\d{1,2}', 46 | reg: /YY/g, 47 | token: 'YY' 48 | }, 49 | { 50 | kind: 'year', 51 | pattern: '[-+]?\\d{1,}', 52 | reg: /Y/g, 53 | token: 'Y' 54 | }, 55 | { 56 | kind: 'quarter', 57 | pattern: '[1-4]', 58 | reg: /Q/g, 59 | token: 'Q' 60 | }, 61 | { 62 | kind: 'month', 63 | // pattern: '\\d{2}', 64 | reg: /MMM/g, 65 | token: 'MMM' 66 | }, 67 | { 68 | kind: 'month', 69 | pattern: '\\d{2}', 70 | reg: /MM/g, 71 | token: 'MM' 72 | }, 73 | { 74 | kind: 'month', 75 | pattern: '\\d{1,2}', 76 | reg: /Mo/g, 77 | token: 'Mo' 78 | }, 79 | { 80 | kind: 'month', 81 | pattern: '\\d{1,2}', 82 | reg: /M/g, 83 | token: 'M' 84 | }, 85 | { 86 | kind: 'day', 87 | pattern: '\\d{2}', 88 | reg: /DD/g, 89 | token: 'DD' 90 | }, 91 | { 92 | kind: 'day', 93 | pattern: '\\d{1,2}', 94 | reg: /D/g, 95 | token: 'D' 96 | }, 97 | { 98 | kind: 'hour', 99 | pattern: '\\d{2}', 100 | reg: /HH/g, 101 | token: 'HH' 102 | }, 103 | { 104 | kind: 'hour', 105 | pattern: '\\d{1,2}', 106 | reg: /H/g, 107 | token: 'H' 108 | }, 109 | { 110 | kind: 'hour', 111 | pattern: '\\d{2}', 112 | reg: /hh/g, 113 | token: 'hh' 114 | }, 115 | { 116 | kind: 'hour', 117 | pattern: '\\d{1,2}', 118 | reg: /h/g, 119 | token: 'h' 120 | }, 121 | { 122 | kind: 'meridiem', 123 | pattern: '\\u0061\\u006D?|\\u0070\\u006D?', 124 | reg: /a/g, 125 | token: 'a' 126 | }, 127 | { 128 | kind: 'meridiem', 129 | pattern: '\\u0061\\u006D?|\\u0070\\u006D?', 130 | reg: /A/g, 131 | token: 'A' 132 | }, 133 | { 134 | kind: 'minute', 135 | pattern: '\\d{2}', 136 | reg: /mm/g, 137 | token: 'mm' 138 | }, 139 | { 140 | kind: 'minute', 141 | pattern: '\\d{1,2}', 142 | reg: /m/g, 143 | token: 'm' 144 | }, 145 | { 146 | kind: 'second', 147 | pattern: '\\d{2}', 148 | reg: /ss/g, 149 | token: 'ss' 150 | }, 151 | { 152 | kind: 'second', 153 | pattern: '\\d{1,2}', 154 | reg: /s/g, 155 | token: 's' 156 | }, 157 | { 158 | kind: 'millisecond', 159 | pattern: '\\d{3}', 160 | reg: /SSS/g, 161 | token: 'SSS' 162 | }, 163 | { 164 | kind: 'millisecond', 165 | pattern: '\\d{2,3}', 166 | reg: /SS/g, 167 | token: 'SS' 168 | }, 169 | { 170 | kind: 'millisecond', 171 | pattern: '\\d{1,3}', 172 | reg: /S/g, 173 | token: 'S' 174 | }, 175 | { 176 | kind: 'offset', 177 | pattern: '[+-]\\d{2}:?\\d{2}|\\u005A', 178 | reg: /ZZ/g, 179 | token: 'ZZ' 180 | }, 181 | { 182 | kind: 'offset', 183 | pattern: '[+-]\\d{2}:?\\d{2}|\\u005A', 184 | reg: /Z/g, 185 | token: 'Z' 186 | } 187 | ]; 188 | 189 | const cache = {}; 190 | 191 | // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex 192 | function escapeRegExp (str) { 193 | return str.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); 194 | } 195 | 196 | /** 197 | * @param {String} timezone 198 | * @returns {DateTime} 199 | * @private 200 | */ 201 | function createCurrentDate (timezone) { 202 | return new DateTime(now(), timezone); 203 | } 204 | 205 | /** 206 | * @returns {Object} 207 | * @private 208 | */ 209 | function getMatch (str, re) { 210 | let idx = re.length; 211 | while (idx--) { 212 | const match = str.match(re[idx]); 213 | if (match) { 214 | return match; 215 | } 216 | } 217 | 218 | return null; 219 | } 220 | 221 | /** 222 | * @param {String} format 223 | * @private 224 | */ 225 | function parseFormat (format) { 226 | if (cache[format]) { 227 | return cache[format]; 228 | } 229 | 230 | let regexStr = escapeRegExp(format); 231 | const origFormat = format; 232 | 233 | const tokens = []; 234 | 235 | function parseToken (token) { 236 | regexStr = regexStr.replace(token.reg, function replaceToken () { 237 | const idx = origFormat.search(token.reg); 238 | tokens.push({ 239 | index: idx, 240 | token: token 241 | }); 242 | 243 | return `(${token.pattern})`; 244 | }); 245 | } 246 | 247 | for (let idx = 0, len = parseTokens.length; idx < len; idx++) { 248 | parseToken(parseTokens[idx]); 249 | } 250 | 251 | const regex = new RegExp(`^${regexStr}$`); 252 | 253 | tokens.sort(function sortTokens (tokenA, tokenB) { 254 | return tokenA.index - tokenB.index; 255 | }); 256 | 257 | const result = { 258 | regex: regex, 259 | tokens: tokens 260 | }; 261 | 262 | cache[format] = result; 263 | 264 | return result; 265 | } 266 | 267 | /** 268 | * Parses given string as a datetime according to ISO-8601 269 | * @param {String} dateTimeStr 270 | * @private 271 | */ 272 | export function parse (dateTimeStr) { 273 | dateTimeStr = trim(dateTimeStr); 274 | 275 | const match = getMatch(dateTimeStr, isoRe); 276 | 277 | if (!match) { 278 | return null; 279 | } 280 | 281 | const date = parseDateStr(match[1]); 282 | const time = parseTimeStr(match[2] || ''); 283 | const offset = parseOffsetStr(match[3] || ''); 284 | 285 | if (date === null || time === null || isNaN(offset)) { 286 | return null; 287 | } 288 | 289 | return [ 290 | date[0], 291 | date[1], 292 | date[2], 293 | time[0], 294 | time[1], 295 | time[2], 296 | time[3], 297 | offset 298 | ]; 299 | } 300 | 301 | /** 302 | * Parses given string as a datetime according to given format 303 | * @param {String} dateTimeStr 304 | * @param {String} format 305 | * @param {String} timezone 306 | * @private 307 | */ 308 | export function parseWithFormat (dateTimeStr, format, timezone) { 309 | const reg = parseFormat(format); 310 | const match = dateTimeStr.match(reg.regex); 311 | const tokens = reg.tokens; 312 | const undef = void 0; 313 | 314 | if (!match) { 315 | return null; 316 | } 317 | 318 | let currDate; 319 | 320 | let useCurrYear = true; 321 | let useCurrMonth = true; 322 | let useCurrDay = true; 323 | let useCurrHour = true; 324 | let useCurrMinute = true; 325 | let useCurrSecond = true; 326 | let useCurrMillisecond = true; 327 | 328 | let year; 329 | let month; 330 | let day; 331 | let hour; 332 | let minute; 333 | let second; 334 | let millisecond; 335 | let offset = null; 336 | 337 | let useMeridiem = false; 338 | let useAm = false; 339 | let usePm = false; 340 | 341 | for (let idx = 1; idx < match.length; idx++) { 342 | const value = match[idx]; 343 | const token = tokens[idx - 1].token; 344 | 345 | switch (token.kind) { 346 | case 'year': 347 | year = Number(value); 348 | if (token.token === 'YY') { 349 | year = 1900 + year; 350 | } 351 | 352 | useCurrYear = false; 353 | useCurrMonth = false; 354 | useCurrDay = false; 355 | useCurrHour = false; 356 | useCurrMinute = false; 357 | useCurrSecond = false; 358 | useCurrMillisecond = false; 359 | 360 | break; 361 | 362 | case 'quarter': 363 | month = Number(value) * 3 - 2; 364 | 365 | useCurrMonth = false; 366 | useCurrDay = false; 367 | useCurrHour = false; 368 | useCurrMinute = false; 369 | useCurrSecond = false; 370 | useCurrMillisecond = false; 371 | 372 | break; 373 | 374 | case 'month': 375 | month = Number(value); 376 | 377 | useCurrMonth = false; 378 | useCurrDay = false; 379 | useCurrHour = false; 380 | useCurrMinute = false; 381 | useCurrSecond = false; 382 | useCurrMillisecond = false; 383 | 384 | break; 385 | 386 | case 'day': 387 | day = Number(value); 388 | 389 | useCurrDay = false; 390 | useCurrHour = false; 391 | useCurrMinute = false; 392 | useCurrSecond = false; 393 | useCurrMillisecond = false; 394 | 395 | break; 396 | 397 | case 'hour': 398 | if (token.token === 'hh' || token.token === 'h') { 399 | useMeridiem = true; 400 | } 401 | 402 | hour = Number(value); 403 | 404 | useCurrHour = false; 405 | useCurrMinute = false; 406 | useCurrSecond = false; 407 | useCurrMillisecond = false; 408 | 409 | break; 410 | 411 | case 'meridiem': 412 | if (value === 'pm' || value === 'p') { 413 | usePm = true; 414 | } else { 415 | useAm = true; 416 | } 417 | 418 | break; 419 | 420 | case 'minute': 421 | minute = Number(value); 422 | 423 | useCurrMinute = false; 424 | useCurrSecond = false; 425 | useCurrMillisecond = false; 426 | 427 | break; 428 | 429 | case 'second': 430 | second = Number(value); 431 | 432 | useCurrSecond = false; 433 | useCurrMillisecond = false; 434 | 435 | break; 436 | 437 | case 'millisecond': 438 | millisecond = Number(value); 439 | 440 | useCurrMillisecond = false; 441 | 442 | break; 443 | 444 | case 'offset': 445 | offset = parseOffsetStr(value); 446 | break; 447 | } 448 | } 449 | 450 | if (useMeridiem) { 451 | if (hour < 1 || hour > 12) { 452 | return null; 453 | } 454 | 455 | if (useAm) { 456 | if (hour === 12) { 457 | hour = 0; 458 | } 459 | } 460 | 461 | if (usePm && hour !== undef) { 462 | if (hour !== 12) { 463 | hour = hour + 12; 464 | } 465 | } 466 | } 467 | 468 | if (useCurrYear || useCurrMonth || useCurrDay || useCurrHour || 469 | useCurrMinute || useCurrSecond || useCurrMillisecond) { 470 | currDate = createCurrentDate(timezone); 471 | } 472 | 473 | if (useCurrYear && year === undef) { 474 | year = currDate.getYear(); 475 | } 476 | 477 | if (useCurrMonth && month === undef) { 478 | month = currDate.getMonth(); 479 | } 480 | 481 | if (useCurrDay && day === undef) { 482 | day = currDate.getDayOfMonth(); 483 | } 484 | 485 | if (useCurrHour && hour === undef) { 486 | hour = currDate.getHour(); 487 | } 488 | 489 | if (useCurrMinute && minute === undef) { 490 | minute = currDate.getMinute(); 491 | } 492 | 493 | if (useCurrSecond && second === undef) { 494 | second = currDate.getSecond(); 495 | } 496 | 497 | if (useCurrMillisecond && millisecond === undef) { 498 | millisecond = currDate.getMillisecond(); 499 | } 500 | 501 | return [ 502 | year, 503 | month !== undef ? month : 1, 504 | day !== undef ? day : 1, 505 | hour !== undef ? hour : 0, 506 | minute !== undef ? minute : 0, 507 | second !== undef ? second : 0, 508 | millisecond !== undef ? millisecond : 0, 509 | offset 510 | ]; 511 | } 512 | 513 | /** 514 | * Parses given string as a date according to ISO-8601 515 | * @param {String} dateStr 516 | * @returns {Array} 517 | * @private 518 | */ 519 | function parseDateStr (dateStr) { 520 | const match = getMatch(dateStr, dateRe); 521 | if (match) { 522 | return [ 523 | Number(match[1]), 524 | Number(match[2] || 1), 525 | Number(match[3] || 1) 526 | ]; 527 | } 528 | 529 | return null; 530 | } 531 | 532 | /** 533 | * @param offsetStr {String} 534 | * @private 535 | */ 536 | function parseOffsetStr (offsetStr) { 537 | if (offsetStr === '') { 538 | return null; 539 | } 540 | 541 | if (offsetStr === 'Z') { 542 | return 0; 543 | } 544 | 545 | let hours; 546 | let minutes; 547 | let sign; 548 | 549 | const match = getMatch(offsetStr, offsetRe); 550 | 551 | if (match) { 552 | sign = match[1]; 553 | hours = Number(match[2]); 554 | minutes = Number(match[4] || 0); 555 | 556 | if (sign === '+') { 557 | return -(hours * 60 + minutes) * 60 * 1000; 558 | } 559 | 560 | return (hours * 60 + minutes) * 60 * 1000; 561 | } 562 | 563 | return NaN; 564 | } 565 | 566 | /** 567 | * Parses given string as a time according to ISO-8601 568 | * @param {String} timeStr 569 | * @returns {Array} 570 | * @private 571 | */ 572 | function parseTimeStr (timeStr) { 573 | if (!timeStr) { 574 | return [0, 0, 0]; 575 | } 576 | 577 | const match = getMatch(timeStr, timeRe); 578 | 579 | if (match) { 580 | return [ 581 | Number(match[1]), 582 | Number(match[2] || 0), 583 | Number(match[3] || 0), 584 | Number(match[5] || 0) 585 | ]; 586 | } 587 | 588 | return null; 589 | } 590 | -------------------------------------------------------------------------------- /src/settings.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ------------------------------------------------------------------------------------- 3 | * Settings 4 | * ------------------------------------------------------------------------------------- 5 | */ 6 | import { 7 | isFiniteNumber, 8 | isValidTzdata, 9 | warn 10 | } from './utils'; 11 | 12 | import { 13 | E_INVALID_TZDATA, 14 | UTC_TIMEZONE, 15 | message 16 | } from './constants'; 17 | 18 | let tzdata = null; 19 | let defaultTimezone = UTC_TIMEZONE; 20 | let locale = 'en'; 21 | 22 | const locales = {}; 23 | 24 | const hasOwnProperty = locales.hasOwnProperty; 25 | 26 | /** 27 | * @param {function} nowFn 28 | * @returns {boolean} 29 | * @inner 30 | */ 31 | function testNow (nowFn) { 32 | return isFiniteNumber(nowFn()); 33 | } 34 | 35 | /** 36 | * @returns {number} 37 | * @inner 38 | */ 39 | function defaultNow () { 40 | return (new Date()).valueOf(); 41 | } 42 | 43 | /** 44 | * @returns {number} 45 | * @public 46 | */ 47 | let nowFn = defaultNow; 48 | 49 | /** 50 | * @param {string} localeName 51 | * @param {Object} localeData 52 | * @public 53 | */ 54 | export function defineLocale (localeName, localeData) { 55 | locales[localeName] = localeData; 56 | } 57 | 58 | /** 59 | * @returns {string} 60 | * @public 61 | */ 62 | export function getDefaultTimezone () { 63 | return defaultTimezone; 64 | } 65 | 66 | /** 67 | * @param {string} timezoneName 68 | * @public 69 | */ 70 | export function setDefaultTimezone (timezoneName) { 71 | defaultTimezone = timezoneName; 72 | } 73 | 74 | /** 75 | * @param {string} localeName 76 | * @public 77 | */ 78 | export function setLocale (localeName) { 79 | if (!hasOwnProperty.call(locales, localeName)) { 80 | throw new Error(`Locale "${localeName}" is not available`); 81 | } 82 | locale = localeName; 83 | } 84 | 85 | /** 86 | * @returns {string} 87 | * @public 88 | */ 89 | export function getLocale () { 90 | return locale; 91 | } 92 | 93 | /** 94 | * @returns {Object} 95 | * @public 96 | */ 97 | export function getLocaleData () { 98 | return locales[locale]; 99 | } 100 | 101 | /** 102 | * @param {string} localeName 103 | * @returns {Object} 104 | * @public 105 | */ 106 | export function getLocaleDataFor (localeName) { 107 | return locales[localeName]; 108 | } 109 | 110 | /** 111 | * @returns {function} nowFn 112 | * @public 113 | */ 114 | export function getNow () { 115 | return nowFn; 116 | } 117 | 118 | /** 119 | * @returns {Object} 120 | * @public 121 | */ 122 | export function getTzdata () { 123 | return tzdata; 124 | } 125 | 126 | /** 127 | * @returns {boolean} 128 | * @public 129 | */ 130 | export function isTzdataSet () { 131 | return Boolean(tzdata); 132 | } 133 | 134 | /** 135 | * @param {Object} newTzdata 136 | * @public 137 | */ 138 | export function setTzdata (newTzdata) { 139 | if (!isValidTzdata(newTzdata)) { 140 | warn(message[E_INVALID_TZDATA](newTzdata)); 141 | return; 142 | } 143 | tzdata = newTzdata; 144 | } 145 | 146 | /** 147 | * @param {function} fn 148 | * @public 149 | */ 150 | export function setNow (fn) { 151 | if (testNow(fn)) { 152 | nowFn = fn; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "../node_modules/eslint-config-dshimkin/default.js", 4 | "../node_modules/eslint-config-dshimkin/jasmine.js" 5 | ], 6 | "parserOptions": { 7 | "sourceType": "script", 8 | "ecmaFeatures": { 9 | "globalReturn": true 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/e2e/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DateTime | Full test 7 | 8 | 46 | 47 | 66 | 67 | 68 | 73 | 74 | 75 | 76 | 77 | 114 | 115 |
116 |
117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /test/e2e/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const chalk = require('chalk'); 4 | const path = require('path'); 5 | const shell = require('shelljs'); 6 | const qunit = require('qunit'); 7 | 8 | const args = Array.prototype.slice.call(process.argv, 2); 9 | 10 | const tzdataVersion = args[0]; 11 | const zoneName = args[1]; 12 | 13 | const skipVersionLog = args.indexOf('--skip-tzdata-version-info') !== -1; 14 | const withCoverage = args.includes('--coverage'); 15 | 16 | /** 17 | * ---------------------------------------------------------------------------------------- 18 | * Validate arguments 19 | * ---------------------------------------------------------------------------------------- 20 | */ 21 | 22 | const tip = 'npm run e2e -- '; 23 | 24 | if (!tzdataVersion) { 25 | console.log(chalk.red('Tzdata version is required')); 26 | console.log(tip); 27 | process.exit(2); 28 | } 29 | 30 | if (!zoneName) { 31 | console.log(chalk.red('Timezone name is required')); 32 | console.log(tip); 33 | process.exit(2); 34 | } 35 | 36 | /** 37 | * ---------------------------------------------------------------------------------------- 38 | * Load tzdata 39 | * ---------------------------------------------------------------------------------------- 40 | */ 41 | 42 | const tzdataKey = (zoneName && zoneName !== 'all') 43 | ? zoneName 44 | : `${tzdataVersion}-all`; 45 | 46 | const tzdataPath = path.resolve(__dirname, `../../node_modules/datetime2-tzdata/tzdata/${tzdataVersion}/js/${tzdataKey}`); 47 | let tzdata; 48 | 49 | try { 50 | tzdata = require(tzdataPath); 51 | } catch (ex) { 52 | console.log(chalk.red(`Could not find "${tzdataPath}"`)); 53 | process.exit(2); 54 | } 55 | 56 | global.tzdata = tzdata; 57 | 58 | if (!skipVersionLog) { 59 | console.log(chalk.blue(`Tzdata ${tzdataVersion}`)); 60 | } 61 | 62 | /** 63 | * ------------------------------------------------------------------------------------------ 64 | * All timezones 65 | * ------------------------------------------------------------------------------------------ 66 | */ 67 | 68 | const testAllZones = zones => { 69 | let current = 0; 70 | const total = zones.length; 71 | 72 | console.log(`Run tests for all ${total} timezones\n`); 73 | 74 | const runTest = () => { 75 | const zone = zones.shift(); 76 | if (zone) { 77 | current = current + 1; 78 | 79 | const cmd = `node test/e2e/run.js ${tzdataVersion} ${zone} --skip-tzdata-version-info`; 80 | 81 | console.log(chalk.blue(`[${current}/${total}] ${zone}`)); 82 | 83 | shell.exec(cmd, {}, (code, output) => { 84 | if (code !== 0) { 85 | process.stdout.write(chalk.red(output)); 86 | process.exit(2); 87 | } 88 | console.log(''); 89 | runTest(); 90 | }); 91 | } 92 | }; 93 | 94 | runTest(); 95 | }; 96 | 97 | if (zoneName === 'all') { 98 | testAllZones(Object.keys(tzdata.zones)); 99 | // eslint-disable-next-line no-use-before-define 100 | return; 101 | } 102 | 103 | /** 104 | * ---------------------------------------------------------------------------------------- 105 | * Configuration 106 | * ---------------------------------------------------------------------------------------- 107 | */ 108 | 109 | qunit.setup({ 110 | coverage: withCoverage, 111 | log: { 112 | coverage: withCoverage, 113 | errors: true, 114 | summary: false 115 | }, 116 | maxBlockDuration: 1000000 117 | }); 118 | 119 | /** 120 | * ---------------------------------------------------------------------------------------- 121 | * Test single timezone 122 | * ---------------------------------------------------------------------------------------- 123 | */ 124 | 125 | const zoneTzdata = tzdata.zones[zoneName]; 126 | 127 | // Zone is required 128 | if (!zoneTzdata) { 129 | console.log(chalk.red(`Timezone ${zoneName} not found in tzdata`)); 130 | process.exit(2); 131 | } 132 | 133 | console.log(chalk.blue(`Test ${zoneName}`)); 134 | 135 | qunit.run({ 136 | deps: [ 137 | `test/e2e/setup.js`, 138 | `node_modules/datetime2-tzdata/tzdata/${tzdataVersion}/js/${tzdataVersion}-all.js`, 139 | `test/e2e/spec/reference/${tzdataVersion}/${zoneName}.js`, 140 | `test/lib/utils/qunit-extend.js` 141 | ], 142 | code: 'dist/datetime.js', 143 | tests: [ 144 | 'test/e2e/spec/index.spec.js' 145 | ] 146 | }, (err, report) => { 147 | if (err) { 148 | console.log(err.message); 149 | process.exit(1); 150 | } 151 | console.log(chalk.green(`${report.passed} tests passed`)); 152 | }); 153 | -------------------------------------------------------------------------------- /test/e2e/setup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | global.DateTime = require('../../dist/datetime'); 4 | -------------------------------------------------------------------------------- /test/e2e/spec/index.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Configuration 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var test = createTestFn(); 11 | 12 | DateTime.setTzdata(tzdata); 13 | 14 | /** 15 | * ---------------------------------------------------------------------------------------- 16 | * Helpers 17 | * ---------------------------------------------------------------------------------------- 18 | */ 19 | 20 | function isArray (arg) { 21 | return {}.toString.call(arg) === '[object Array]'; 22 | } 23 | 24 | function equalDateAttrs (attrsA, attrsB) { 25 | if (isArray(attrsA) && isArray(attrsB) && attrsA.length === attrsB.length) { 26 | for (var idx = 0, len = attrsA.length; idx < len; idx++) { 27 | if (attrsA[idx] !== attrsB[idx]) { 28 | return false; 29 | } 30 | } 31 | return true; 32 | } 33 | return false; 34 | } 35 | 36 | /** 37 | * ---------------------------------------------------------------------------------------- 38 | * Specs 39 | * ---------------------------------------------------------------------------------------- 40 | */ 41 | 42 | function testGroup (group) { 43 | var caseIdx; 44 | var groupLen; 45 | 46 | function testDateToMoment (testCase) { 47 | test('[' + group.zone + '] Date to moment :: ' + testCase.date, function () { 48 | var properTimestamp = testCase.timestamp; 49 | 50 | DateTime.setDefaultTimezone(group.zone); 51 | 52 | var dt = new DateTime(testCase.date); 53 | 54 | ok(dt.valueOf() === properTimestamp); 55 | }); 56 | } 57 | 58 | function testMomentToDate (testCase) { 59 | test('[' + group.zone + '] Moment to date :: ' + testCase.date, function () { 60 | var properTimestamp = testCase.timestamp; 61 | 62 | DateTime.setDefaultTimezone(group.zone); 63 | 64 | var dt = new DateTime(properTimestamp); 65 | var date = [ 66 | dt.getYear(), 67 | dt.getMonth(), 68 | dt.getDayOfMonth(), 69 | dt.getHour(), 70 | dt.getMinute(), 71 | dt.getSecond(), 72 | dt.getMillisecond() 73 | ]; 74 | 75 | ok(equalDateAttrs(date, testCase.date)); 76 | }); 77 | } 78 | 79 | // Date to moment 80 | for (caseIdx = 0, groupLen = group.dateArray.length; caseIdx < groupLen; caseIdx++) { 81 | testDateToMoment(group.dateArray[caseIdx]); 82 | } 83 | 84 | // Moment to date 85 | for (caseIdx = 0, groupLen = group.dateArray.length; caseIdx < groupLen; caseIdx++) { 86 | testMomentToDate(group.dateArray[caseIdx]); 87 | } 88 | 89 | // Formatted string to date 90 | function testStringToDate (testCase) { 91 | test('[' + group.zone + '] String to date :: ' + testCase.dateStr, function () { 92 | DateTime.setDefaultTimezone(group.zone); 93 | 94 | var dt = new DateTime(testCase.dateStr); 95 | var date = [ 96 | dt.getYear(), 97 | dt.getMonth(), 98 | dt.getDayOfMonth(), 99 | dt.getHour(), 100 | dt.getMinute(), 101 | dt.getSecond(), 102 | dt.getMillisecond() 103 | ]; 104 | 105 | ok(date.toString() === testCase.date.toString()); 106 | }); 107 | } 108 | 109 | // Tests all formats 110 | for (var groupKey in group) { 111 | if ({}.hasOwnProperty.call(group, groupKey)) { 112 | if (groupKey !== 'dateArray' && groupKey !== 'zone') { 113 | var cases = group[groupKey]; 114 | for (caseIdx = 0, groupLen = cases.length; caseIdx < groupLen; caseIdx++) { 115 | if (cases[caseIdx].dateStr.match(/00$/)) { 116 | testStringToDate(cases[caseIdx]); 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } 123 | 124 | for (var groupIdx = 0, groupLen = testData.length; groupIdx < groupLen; groupIdx++) { 125 | testGroup(testData[groupIdx]); 126 | } 127 | })(); 128 | -------------------------------------------------------------------------------- /test/lib/qunit/qunit.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * QUnit 1.14.0 3 | * http://qunitjs.com/ 4 | * 5 | * Copyright 2013 jQuery Foundation and other contributors 6 | * Released under the MIT license 7 | * http://jquery.org/license 8 | * 9 | * Date: 2014-01-31T16:40Z 10 | */ 11 | 12 | /** Font Family and Sizes */ 13 | 14 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 15 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 16 | } 17 | 18 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 19 | #qunit-tests { font-size: smaller; } 20 | 21 | 22 | /** Resets */ 23 | 24 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { 25 | margin: 0; 26 | padding: 0; 27 | } 28 | 29 | 30 | /** Header */ 31 | 32 | #qunit-header { 33 | padding: 0.5em 0 0.5em; 34 | color: #8699A4; 35 | font-size: 1.5em; 36 | line-height: 1em; 37 | font-weight: 400; 38 | } 39 | 40 | #qunit-header a { 41 | color: #0d3349; 42 | text-decoration: none; 43 | } 44 | 45 | #qunit-testrunner-toolbar label { 46 | display: inline-block; 47 | padding: 0 0.5em 0 0.1em; 48 | } 49 | 50 | #qunit-banner { 51 | height: 5px; 52 | } 53 | 54 | #qunit-testrunner-toolbar { 55 | padding: 1em 1em 1em 1.5em; 56 | color: #5E740B; 57 | background-color: #EEE; 58 | overflow: hidden; 59 | } 60 | 61 | #qunit-userAgent { 62 | display: none; 63 | } 64 | 65 | #qunit-modulefilter-container { 66 | float: right; 67 | } 68 | 69 | /** Tests: Pass/Fail */ 70 | 71 | #qunit-tests { 72 | list-style-position: inside; 73 | } 74 | 75 | #qunit-tests li { 76 | font-size: 14px; 77 | padding: 1em 1.5em; 78 | border-bottom: 1px solid #FFF; 79 | list-style-position: inside; 80 | } 81 | 82 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 83 | display: none; 84 | } 85 | 86 | #qunit-tests li strong { 87 | cursor: pointer; 88 | font-weight: normal; 89 | } 90 | 91 | #qunit-tests li b { 92 | font-weight: normal; 93 | } 94 | 95 | #qunit-tests li a { 96 | padding: 0.5em; 97 | color: #C2CCD1; 98 | text-decoration: none; 99 | } 100 | #qunit-tests li a:hover, 101 | #qunit-tests li a:focus { 102 | color: #000; 103 | } 104 | 105 | #qunit-tests li .runtime { 106 | float: right; 107 | font-size: smaller; 108 | } 109 | 110 | .qunit-assert-list { 111 | margin-top: 0.5em; 112 | padding: 0.5em; 113 | 114 | background-color: #FFF; 115 | 116 | border-radius: 5px; 117 | } 118 | 119 | .qunit-collapsed { 120 | display: none; 121 | } 122 | 123 | #qunit-tests table { 124 | border-collapse: collapse; 125 | margin-top: 0.2em; 126 | } 127 | 128 | #qunit-tests th { 129 | text-align: right; 130 | vertical-align: top; 131 | padding: 0 0.5em 0 0; 132 | } 133 | 134 | #qunit-tests td { 135 | vertical-align: top; 136 | } 137 | 138 | #qunit-tests pre { 139 | margin: 0; 140 | white-space: pre-wrap; 141 | word-wrap: break-word; 142 | } 143 | 144 | #qunit-tests del { 145 | background-color: #E0F2BE; 146 | color: #374E0C; 147 | text-decoration: none; 148 | } 149 | 150 | #qunit-tests ins { 151 | background-color: #FFCACA; 152 | color: #500; 153 | text-decoration: none; 154 | } 155 | 156 | /*** Test Counts */ 157 | 158 | #qunit-tests b.counts { color: #000; } 159 | #qunit-tests b.passed { color: #5E740B; } 160 | #qunit-tests b.failed { color: #710909; } 161 | 162 | #qunit-tests li li { 163 | padding: 5px; 164 | background-color: #FFF; 165 | border-bottom: none; 166 | list-style-position: inside; 167 | } 168 | 169 | /*** Passing Styles */ 170 | 171 | #qunit-tests li li.pass { 172 | color: #3C510C; 173 | background-color: #FFF; 174 | border-left: 10px solid #C6E746; 175 | } 176 | 177 | #qunit-tests .pass { color: #528CE0; background-color: #f0f0f0; } 178 | #qunit-tests .pass .test-name { color: #366097; } 179 | 180 | #qunit-tests .pass .test-actual, 181 | #qunit-tests .pass .test-expected { color: #999; } 182 | 183 | #qunit-banner.qunit-pass { background-color: #C6E746; } 184 | 185 | /*** Failing Styles */ 186 | 187 | #qunit-tests li li.fail { 188 | color: #710909; 189 | background-color: #FFF; 190 | border-left: 10px solid #EE5757; 191 | white-space: pre; 192 | } 193 | 194 | #qunit-tests > li:last-child { 195 | border-radius: 0 0 5px 5px; 196 | } 197 | 198 | #qunit-tests .fail { color: #000; background-color: #EE5757; } 199 | #qunit-tests .fail .test-name, 200 | #qunit-tests .fail .module-name { color: #000; } 201 | 202 | #qunit-tests .fail .test-actual { color: #EE5757; } 203 | #qunit-tests .fail .test-expected { color: #008000; } 204 | 205 | #qunit-banner.qunit-fail { background-color: #EE5757; } 206 | 207 | 208 | /** Result */ 209 | 210 | #qunit-testresult { 211 | padding: 1em 0.5em 1em 1.5em; 212 | 213 | color: #2B81AF; 214 | background-color: #D2E0E6; 215 | 216 | border-bottom: 1px solid #FFF; 217 | } 218 | #qunit-testresult .module-name { 219 | font-weight: 700; 220 | } 221 | 222 | /** Fixture */ 223 | 224 | #qunit-fixture { 225 | position: absolute; 226 | top: -10000px; 227 | left: -10000px; 228 | width: 1000px; 229 | height: 1000px; 230 | } 231 | -------------------------------------------------------------------------------- /test/lib/utils/qunit-extend.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * ---------------------------------------------------------------------------------------- 5 | * QUnit extras 6 | * ---------------------------------------------------------------------------------------- 7 | */ 8 | 9 | var qunitTest = test; 10 | 11 | function createTestFn () { 12 | return qunitTest; 13 | } 14 | 15 | /** 16 | * CommonJS module 17 | */ 18 | if (typeof exports === 'object') { 19 | module.exports = { createTestFn: createTestFn }; 20 | } 21 | 22 | if (typeof global === 'object') { 23 | global.createTestFn = createTestFn; 24 | } 25 | -------------------------------------------------------------------------------- /test/lib/utils/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var TEST_TIMEZONE = 'TEST_TIMEZONE'; 4 | 5 | function isArray (arg) { 6 | return {}.toString.call(arg) === '[object Array]'; 7 | } 8 | 9 | function equalArrays (arg1, arg2) { 10 | if (!isArray(arg1) || !isArray(arg2)) { 11 | return false; 12 | } 13 | 14 | if (arg1.length !== arg2.length) { 15 | return false; 16 | } 17 | 18 | var idx = arg1.length; 19 | 20 | while (idx--) { 21 | if (arg1[idx] !== arg2[idx]) { 22 | return false; 23 | } 24 | } 25 | 26 | return true; 27 | } 28 | 29 | function equalDates (date1, date2) { 30 | return ( 31 | date1.valueOf() === date2.valueOf() && 32 | date1.getTimezoneName() === date2.getTimezoneName() && 33 | date1.getTimezoneOffset() === date2.getTimezoneOffset() && 34 | date1.getTimezoneAbbr() === date2.getTimezoneAbbr() && 35 | date1.isDST() === date2.isDST() && 36 | date1.getYear() === date2.getYear() && 37 | date1.getMonth() === date2.getMonth() && 38 | date1.getDayOfMonth() === date2.getDayOfMonth() && 39 | date1.getHour() === date2.getHour() && 40 | date1.getMinute() === date2.getMinute() && 41 | date1.getSecond() === date2.getSecond() && 42 | date1.getMillisecond() === date2.getMillisecond() && 43 | date1.getUTCYear() === date2.getUTCYear() && 44 | date1.getUTCMonth() === date2.getUTCMonth() && 45 | date1.getUTCDayOfMonth() === date2.getUTCDayOfMonth() && 46 | date1.getUTCHour() === date2.getUTCHour() && 47 | date1.getUTCMinute() === date2.getUTCMinute() && 48 | date1.getUTCSecond() === date2.getUTCSecond() && 49 | date1.getUTCMillisecond() === date2.getUTCMillisecond() 50 | ); 51 | } 52 | 53 | function mockNow (now) { 54 | DateTime.setNow(function nowMock () { 55 | return now; 56 | }); 57 | } 58 | 59 | function setTestTimezone (params) { 60 | tzdata.zones[TEST_TIMEZONE] = { 61 | abbr: params.abbr || ['TST', 'TST'], 62 | dst: params.dst, 63 | name: TEST_TIMEZONE, 64 | offset: params.offset, 65 | until: params.until 66 | }; 67 | } 68 | 69 | if (typeof exports === 'object') { 70 | module.exports = { 71 | equalArrays: equalArrays, 72 | equalDates: equalDates, 73 | mockNow: mockNow 74 | }; 75 | } 76 | 77 | if (typeof global === 'object') { 78 | global.TEST_TIMEZONE = TEST_TIMEZONE; 79 | 80 | global.equalArrays = equalArrays; 81 | global.equalDates = equalDates; 82 | global.mockNow = mockNow; 83 | global.setTestTimezone = setTestTimezone; 84 | } 85 | -------------------------------------------------------------------------------- /test/readme.md: -------------------------------------------------------------------------------- 1 | # Test 2 | 3 | ## Unit tests 4 | 5 | #### Browser environment 6 | 7 | Open [test/unit/index.html](./test/unit/index.html) page in the browser. 8 | 9 | Tests should work in any ES3-compliant browser starting from IE 5.5, Safari 3, and FF 2. 10 | 11 | 12 | #### NodeJS environment 13 | 14 | Run unit tests: 15 | 16 | ``` 17 | npm run unit 18 | ``` 19 | 20 | Run unit tests and generate code coverage report: 21 | 22 | ``` 23 | npm run cov 24 | ``` 25 | 26 | This command runs the unit tests, then prints the code coverage report 27 | into the stdout, and writes it also into a [coverage](./coverage) directory. 28 | 29 | ## E2E tests 30 | 31 | E2E tests run against pre-defined reference collection of dates. 32 | 33 | ### Prerequisites 34 | 35 | To run E2E tests first you need to generate them: 36 | 37 | npm run gen -- --version --timezone 38 | 39 | where ```` is the version of tzdata, and ```` 40 | is the name of timezone. 41 | 42 | Examples: 43 | 44 | # Generate test dates for Europe/Amsterdam 45 | npm run gen -- --version 2017a --timezone Europe/Amsterdam 46 | 47 | # Generate test dates for all timezones 48 | npm run gen -- --version 2017a --timezone all 49 | 50 | Generated references will be saved in `test/e2e/spec/reference` directory. 51 | 52 | NOTE: On Macbook Pro it takes **1 hour** to generate all the test references, and **4 hours** 53 | to run the tests. Generated test references take **7 GB** of disk space. 54 | 55 | ### Run in browser 56 | 57 | Open [test/e2e/index.html](test/e2e/index.html) in browser and select a timezone 58 | in the navigation menu. 59 | 60 | Tests should work in any ES3-compliant browser starting from IE 5.5, Safari 3, and FF 2. 61 | 62 | ### Run in node 63 | 64 | Run the following command to run E2E tests for specific timezone: 65 | 66 | ``` 67 | npm run e2e -- 2017a Europe/Amsterdam 68 | ``` 69 | 70 | Replace _2017a_ and _Europe/Amsterdam_ with needed tzdata version and timezone name. 71 | 72 | NOTE: Code coverage is not available for E2E tests. 73 | -------------------------------------------------------------------------------- /test/unit/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DateTime | Unit test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /test/unit/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const qunit = require('qunit'); 4 | 5 | /** 6 | * ---------------------------------------------------------------------------------------- 7 | * Parse arguments 8 | * ---------------------------------------------------------------------------------------- 9 | */ 10 | 11 | const args = Array.prototype.slice.call(process.argv, 2); 12 | const withCoverage = args.includes('--coverage'); 13 | 14 | const specPath = 'test/unit/spec'; 15 | 16 | /** 17 | * ---------------------------------------------------------------------------------------- 18 | * Prepare configuration 19 | * ---------------------------------------------------------------------------------------- 20 | */ 21 | 22 | qunit.setup({ 23 | coverage: withCoverage, 24 | log: { 25 | coverage: withCoverage, 26 | errors: true, 27 | summary: true 28 | }, 29 | maxBlockDuration: 20000 30 | }); 31 | 32 | /** 33 | * ---------------------------------------------------------------------------------------- 34 | * Run tests 35 | * ---------------------------------------------------------------------------------------- 36 | */ 37 | 38 | qunit.run({ 39 | code: 'dist/datetime.js', 40 | deps: [ 41 | 'test/unit/setup.js', 42 | 'test/lib/utils/qunit-extend.js', 43 | 'test/lib/utils/utils.js' 44 | ], 45 | tests: [ 46 | `${specPath}/clone.spec.js`, 47 | `${specPath}/create-instance.spec.js`, 48 | `${specPath}/format.spec.js`, 49 | `${specPath}/getters.spec.js`, 50 | `${specPath}/invalid.spec.js`, 51 | `${specPath}/is.spec.js`, 52 | `${specPath}/misc.spec.js`, 53 | `${specPath}/now.spec.js`, 54 | `${specPath}/parse.spec.js`, 55 | `${specPath}/setters.spec.js`, 56 | `${specPath}/timezone-default.spec.js`, 57 | `${specPath}/timezone-info.spec.js`, 58 | `${specPath}/transform.spec.js`, 59 | `${specPath}/transform-to.spec.js`, 60 | `${specPath}/duration/duration.spec.js`, 61 | `${specPath}/interval/interval.spec.js`, 62 | `${specPath}/calendar/second.spec.js`, 63 | `${specPath}/calendar/minute.spec.js`, 64 | `${specPath}/calendar/hour.spec.js`, 65 | `${specPath}/calendar/day.spec.js`, 66 | `${specPath}/calendar/week.spec.js`, 67 | `${specPath}/calendar/month.spec.js`, 68 | `${specPath}/calendar/month-weeks.spec.js`, 69 | `${specPath}/calendar/year.spec.js`, 70 | `${specPath}/locale.spec.js`, 71 | `${specPath}/locale/en.spec.js`, 72 | `${specPath}/locale/ru.spec.js` 73 | ] 74 | }); 75 | -------------------------------------------------------------------------------- /test/unit/setup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * ------------------------------------------------------------------------------------------ 5 | * Expose DateTime to globals 6 | * ------------------------------------------------------------------------------------------ 7 | */ 8 | 9 | const distPath = '../../dist'; 10 | const nodeModulesPath = '../../node_modules'; 11 | 12 | const localeRu = require(`${nodeModulesPath}/datetime2-locale-ru/ru`); 13 | 14 | global.DateTime = require(`${distPath}/datetime`); 15 | global.tzdata = require(`${nodeModulesPath}/datetime2-tzdata/tzdata/2017a/js/2017a-all`); 16 | 17 | DateTime.setTzdata(tzdata); 18 | DateTime.defineLocale('ru', localeRu); 19 | 20 | // Suppress console warnings 21 | console.warn = function () {}; 22 | -------------------------------------------------------------------------------- /test/unit/spec/calendar/minute.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var UTC_TIMEZONE = 'UTC'; 11 | 12 | var test = createTestFn(); 13 | 14 | var Minute = DateTime.Minute; 15 | var Interval = DateTime.Interval; 16 | 17 | /** 18 | * ---------------------------------------------------------------------------------------- 19 | * Class 20 | * ---------------------------------------------------------------------------------------- 21 | */ 22 | 23 | test('[Minute] Class', function () { 24 | ok(typeof Minute === 'function'); 25 | }); 26 | 27 | /** 28 | * ---------------------------------------------------------------------------------------- 29 | * Create 30 | * ---------------------------------------------------------------------------------------- 31 | */ 32 | 33 | test('[Minute] Create :: No arguments', function () { 34 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 35 | 36 | mockNow(880235000); 37 | 38 | var minute = new Minute(); 39 | 40 | ok(minute instanceof Minute); 41 | ok(minute instanceof Interval); 42 | 43 | ok(minute.toStart().isEqual(new DateTime([1970, 1, 11, 4, 30, 0, 0]))); 44 | ok(minute.toEnd().isEqual(new DateTime([1970, 1, 11, 4, 31, 0, 0]))); 45 | }); 46 | 47 | test('[Minute] Create :: DateTime', function () { 48 | var dt = new DateTime([1970, 1, 11, 14, 25, 15, 0], UTC_TIMEZONE); 49 | 50 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 51 | 52 | var minute = new Minute(dt); 53 | 54 | ok(minute.toStart() !== dt); 55 | ok(minute.toStart().isEqual(new DateTime([1970, 1, 11, 14, 25, 0, 0])) === true); 56 | ok(minute.toEnd().isEqual(new DateTime([1970, 1, 11, 14, 26, 0, 0])) === true); 57 | 58 | // Original date shouldn't be altered 59 | ok(dt.isEqual(new DateTime([1970, 1, 11, 14, 25, 15, 0])) === true); 60 | }); 61 | 62 | test('[Minute] Create :: String', function () { 63 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 64 | 65 | var minute = new Minute('1970-01-11'); 66 | 67 | ok(minute.toStart().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0]))); 68 | ok(minute.toEnd().isEqual(new DateTime([1970, 1, 11, 0, 1, 0, 0]))); 69 | }); 70 | 71 | test('[Minute] Create :: Number', function () { 72 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 73 | 74 | var minute = new Minute(914420000); 75 | 76 | ok(minute.toStart().isEqual(new DateTime([1970, 1, 11, 14, 0, 0, 0]))); 77 | ok(minute.toEnd().isEqual(new DateTime([1970, 1, 11, 14, 1, 0, 0]))); 78 | }); 79 | 80 | test('[Minute] Create :: String and timezone', function () { 81 | setTestTimezone({ 82 | abbr: [ 83 | 'TST', 84 | 'TST_1', 85 | 'TST' 86 | ], 87 | dst: [ 88 | false, 89 | true, 90 | false 91 | ], 92 | offset: [ 93 | 0, 94 | -60, // +0100 95 | 0 96 | ], 97 | until: [ 98 | 180000000, // 1970-01-03T02:00:00 99 | 262800000, // 1970-01-04T02:00:00 100 | null 101 | ] 102 | }); 103 | 104 | var minute = new Minute('1970-01-03T03:27:00+0100', TEST_TIMEZONE); 105 | 106 | ok(minute.toStart().isEqual(new DateTime([1970, 1, 3, 3, 27, 0, 0], TEST_TIMEZONE))); 107 | ok(minute.toEnd().isEqual(new DateTime([1970, 1, 3, 3, 28, 0, 0], TEST_TIMEZONE))); 108 | }); 109 | 110 | /** 111 | * ---------------------------------------------------------------------------------------- 112 | * Getters 113 | * ---------------------------------------------------------------------------------------- 114 | */ 115 | 116 | test('[Minute] getMinute', function () { 117 | var minute = new Minute('1979-05-03T11:55:44+0100', UTC_TIMEZONE); 118 | ok(minute.getMinute() === 55); 119 | }); 120 | 121 | test('[Minute] getHour', function () { 122 | var minute = new Minute('1979-05-03T11:00:44+0100', UTC_TIMEZONE); 123 | ok(minute.getHour() === 10); 124 | }); 125 | 126 | test('[Minute] getDayOfWeek', function () { 127 | var minute; 128 | 129 | minute = new Minute('1979-04-29T03:00:44+0100', UTC_TIMEZONE); 130 | ok(minute.getDayOfWeek() === 0); 131 | 132 | minute = new Minute('1979-05-05T03:00:44+0100', UTC_TIMEZONE); 133 | ok(minute.getDayOfWeek() === 6); 134 | }); 135 | 136 | test('[Minute] getDayOfMonth', function () { 137 | var minute = new Minute('1979-05-03T03:00:44+0100', UTC_TIMEZONE); 138 | ok(minute.getDayOfMonth() === 3); 139 | }); 140 | 141 | test('[Minute] getMonth', function () { 142 | var minute = new Minute('1979-05-03T03:00:44+0100', UTC_TIMEZONE); 143 | ok(minute.getMonth() === 5); 144 | }); 145 | 146 | test('[Minute] getYear', function () { 147 | var minute = new Minute('1979-01-03T03:00:44+0100', UTC_TIMEZONE); 148 | ok(minute.getYear() === 1979); 149 | }); 150 | 151 | /** 152 | * ---------------------------------------------------------------------------------------- 153 | * Next minute 154 | * ---------------------------------------------------------------------------------------- 155 | */ 156 | 157 | test('[Minute] toNext', function () { 158 | var minute = new Minute('1970-01-03T03:59:59+0100', UTC_TIMEZONE); 159 | var nextMinute = minute.toNext(); 160 | 161 | ok(nextMinute !== minute); 162 | 163 | ok(nextMinute.toStart().isEqual(new DateTime([1970, 1, 3, 3, 0, 0, 0]))); 164 | ok(nextMinute.toEnd().isEqual(new DateTime([1970, 1, 3, 3, 1, 0, 0]))); 165 | 166 | // Original minute isn't altered 167 | ok(minute.toStart().isEqual(new DateTime([1970, 1, 3, 2, 59, 0, 0]))); 168 | ok(minute.toEnd().isEqual(new DateTime([1970, 1, 3, 3, 0, 0, 0]))); 169 | }); 170 | 171 | test('[Minute] toNext :: Next month', function () { 172 | var minute = new Minute('1970-01-31T23:58:59', UTC_TIMEZONE); 173 | var nextMinute = minute.toNext(); 174 | 175 | ok(nextMinute.toStart().isEqual(new DateTime([1970, 1, 31, 23, 59, 0, 0]))); 176 | ok(nextMinute.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 177 | }); 178 | 179 | test('[Minute] toNext :: Next year', function () { 180 | var minute = new Minute('2016-12-31T23:58:59', UTC_TIMEZONE); 181 | var nextMinute = minute.toNext(); 182 | 183 | ok(nextMinute.toStart().isEqual(new DateTime([2016, 12, 31, 23, 59, 0, 0]))); 184 | ok(nextMinute.toEnd().isEqual(new DateTime([2017, 1, 1, 0, 0, 0, 0]))); 185 | }); 186 | 187 | test('[Minute] toNext :: Timezone', function () { 188 | setTestTimezone({ 189 | abbr: [ 190 | 'TST', 191 | 'TST_1', 192 | 'TST' 193 | ], 194 | dst: [ 195 | false, 196 | true, 197 | false 198 | ], 199 | offset: [ 200 | 0, 201 | -60, // +0100 202 | 0 203 | ], 204 | until: [ 205 | 180000000, // 1970-01-03T02:00:00 206 | 262800000, // 1970-01-04T02:00:00 207 | null 208 | ] 209 | }); 210 | 211 | var minute = new Minute('1970-01-03T00:30:45', TEST_TIMEZONE); 212 | var nextMinute = minute.toNext(); 213 | 214 | ok(nextMinute !== minute); 215 | 216 | ok(nextMinute.toStart().isEqual(new DateTime([1970, 1, 3, 0, 31, 0, 0], TEST_TIMEZONE))); 217 | ok(nextMinute.toEnd().isEqual(new DateTime([1970, 1, 3, 0, 32, 0, 0], TEST_TIMEZONE))); 218 | }); 219 | 220 | /** 221 | * ---------------------------------------------------------------------------------------- 222 | * Previous minute 223 | * ---------------------------------------------------------------------------------------- 224 | */ 225 | 226 | test('[Minute] toPrev', function () { 227 | var minute = new Minute('1970-01-03T03:00:00', UTC_TIMEZONE); 228 | var prevMinute = minute.toPrev(); 229 | 230 | ok(prevMinute !== minute); 231 | 232 | ok(prevMinute.toStart().isEqual(new DateTime([1970, 1, 3, 2, 59, 0, 0]))); 233 | ok(prevMinute.toEnd().isEqual(new DateTime([1970, 1, 3, 3, 0, 0, 0]))); 234 | 235 | // Original minute isn't altered 236 | ok(minute.toStart().isEqual(new DateTime([1970, 1, 3, 3, 0, 0, 0]))); 237 | ok(minute.toEnd().isEqual(new DateTime([1970, 1, 3, 3, 1, 0, 0]))); 238 | }); 239 | 240 | test('[Minute] toPrev :: Previous month', function () { 241 | var minute = new Minute('1970-02-01T00:00:30', UTC_TIMEZONE); 242 | var prevMinute = minute.toPrev(); 243 | 244 | ok(prevMinute.toStart().isEqual(new DateTime([1970, 1, 31, 23, 59, 0, 0]))); 245 | ok(prevMinute.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 246 | }); 247 | 248 | test('[Minute] toPrev :: Previous year', function () { 249 | var minute = new Minute('2017-01-01T00:00:00', UTC_TIMEZONE); 250 | var prevMinute = minute.toPrev(); 251 | 252 | ok(prevMinute.toStart().isEqual(new DateTime([2016, 12, 31, 23, 59, 0, 0]))); 253 | ok(prevMinute.toEnd().isEqual(new DateTime([2017, 1, 1, 0, 0, 0, 0]))); 254 | }); 255 | 256 | test('[Minute] toPrev :: Timezone', function () { 257 | setTestTimezone({ 258 | abbr: [ 259 | 'TST', 260 | 'TST_1', 261 | 'TST' 262 | ], 263 | dst: [ 264 | false, 265 | true, 266 | false 267 | ], 268 | offset: [ 269 | 0, 270 | -60, // +0100 271 | 0 272 | ], 273 | until: [ 274 | 180000000, // 1970-01-03T02:00:00 275 | 262800000, // 1970-01-04T02:00:00 276 | null 277 | ] 278 | }); 279 | 280 | var minute = new Minute('1970-01-03T03:00:00', TEST_TIMEZONE); 281 | var prevMinute = minute.toPrev(); 282 | 283 | ok(prevMinute !== minute); 284 | 285 | ok(prevMinute.toStart().isEqual(new DateTime('1970-01-03T01:59:00+0000', TEST_TIMEZONE))); 286 | ok(prevMinute.toEnd().isEqual(new DateTime('1970-01-03T03:00:00+0100', TEST_TIMEZONE))); 287 | ok(prevMinute.valueOf() === 60000); 288 | }); 289 | 290 | /** 291 | * ---------------------------------------------------------------------------------------- 292 | * toSeconds 293 | * ---------------------------------------------------------------------------------------- 294 | */ 295 | 296 | test('[Minute] toSeconds', function () { 297 | var minute = new Minute('2017-05-15T14:30:00', UTC_TIMEZONE); 298 | var seconds = minute.toSeconds(); 299 | var idx = seconds.length; 300 | 301 | var expectedMinute; 302 | var expectedSecond; 303 | 304 | ok(seconds.length === 60); 305 | 306 | while (idx--) { 307 | ok(seconds[idx].toStart().isEqual( 308 | new DateTime([2017, 5, 15, 14, 30, idx, 0], UTC_TIMEZONE) 309 | )); 310 | 311 | expectedMinute = idx === 59 ? 31 : 30; 312 | expectedSecond = idx === 59 ? 0 : idx + 1; 313 | 314 | ok(seconds[idx].toEnd().isEqual( 315 | new DateTime([2017, 5, 15, 14, expectedMinute, expectedSecond, 0], UTC_TIMEZONE) 316 | )); 317 | } 318 | }); 319 | 320 | /** 321 | * ---------------------------------------------------------------------------------------- 322 | * Display 323 | * ---------------------------------------------------------------------------------------- 324 | */ 325 | 326 | test('[Minute] Display :: format', function () { 327 | var minute = new Minute('1970-01-03T03:00:00', UTC_TIMEZONE); 328 | ok(minute.format('YYYY-MM-DD') === '1970-01-03 – 1970-01-03'); 329 | }); 330 | 331 | test('[Minute] Display :: toISOString', function () { 332 | var minute = new Minute('1970-01-03T03:00:00', UTC_TIMEZONE); 333 | ok(minute.toISOString() === '1970-01-03T03:00:00.000Z – 1970-01-03T03:01:00.000Z'); 334 | }); 335 | 336 | test('[Minute] Display :: toLocaleString', function () { 337 | var minute = new Minute('1970-01-03T03:25:00', UTC_TIMEZONE); 338 | ok(minute.toLocaleString() === '1/3/1970, 3:25:00 AM – 1/3/1970, 3:26:00 AM'); 339 | }); 340 | 341 | test('[Minute] Display :: toString', function () { 342 | var minute = new Minute('1970-01-03T23:59:00', UTC_TIMEZONE); 343 | ok(minute.toString() === 'Sat Jan 03 1970 23:59:00 GMT+0000 (UTC) – Sun Jan 04 1970 00:00:00 GMT+0000 (UTC)'); 344 | }); 345 | 346 | test('[Minute] Display :: toUTCString', function () { 347 | var minute = new Minute('1970-01-03T14:59:45', UTC_TIMEZONE); 348 | ok(minute.toUTCString() === 'Sat, 03 Jan 1970 14:59:00 GMT – Sat, 03 Jan 1970 15:00:00 GMT'); 349 | }); 350 | 351 | /** 352 | * ---------------------------------------------------------------------------------------- 353 | * Other methods 354 | * ---------------------------------------------------------------------------------------- 355 | */ 356 | 357 | test('[Minute] toJSON', function () { 358 | var minute = new Minute('2016-05-01T14:30:59', UTC_TIMEZONE); 359 | ok(minute.toJSON() === 'Sun May 01 2016 14:30:00 GMT+0000 (UTC) – Sun May 01 2016 14:31:00 GMT+0000 (UTC)'); 360 | }); 361 | 362 | test('[Minute] valueOf', function () { 363 | setTestTimezone({ 364 | abbr: [ 365 | 'TST', 366 | 'TST_1', 367 | 'TST' 368 | ], 369 | dst: [ 370 | false, 371 | true, 372 | false 373 | ], 374 | offset: [ 375 | 0, 376 | -60, // +0100 377 | 0 378 | ], 379 | until: [ 380 | 180000000, // 1970-01-03T02:00:00 381 | 262800000, // 1970-01-04T02:00:00 382 | null 383 | ] 384 | }); 385 | 386 | var minute = new Minute('2016-08-01T12:59:59.444', UTC_TIMEZONE); 387 | ok(minute.valueOf() === 60000); 388 | 389 | minute = new Minute('1970-01-03T02:59:59+0100', TEST_TIMEZONE); 390 | ok(minute.valueOf() === 60000); 391 | }); 392 | })(); 393 | -------------------------------------------------------------------------------- /test/unit/spec/calendar/month-weeks.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var UTC_TIMEZONE = 'UTC'; 11 | 12 | var test = createTestFn(); 13 | 14 | var MonthWeeks = DateTime.MonthWeeks; 15 | var Interval = DateTime.Interval; 16 | 17 | var monthWeeks; 18 | var weeks; 19 | 20 | /** 21 | * ---------------------------------------------------------------------------------------- 22 | * Class 23 | * ---------------------------------------------------------------------------------------- 24 | */ 25 | 26 | test('[MonthWeeks] Class', function () { 27 | ok(typeof MonthWeeks === 'function'); 28 | }); 29 | 30 | /** 31 | * ---------------------------------------------------------------------------------------- 32 | * Create 33 | * ---------------------------------------------------------------------------------------- 34 | */ 35 | 36 | test('[MonthWeeks] Create :: No arguments', function () { 37 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 38 | 39 | mockNow(8640000000); 40 | 41 | monthWeeks = new MonthWeeks(); 42 | 43 | ok(monthWeeks instanceof MonthWeeks); 44 | ok(monthWeeks instanceof Interval); 45 | 46 | ok(monthWeeks.toStart().isEqual(new DateTime([1970, 3, 29, 0, 0, 0, 0]))); 47 | ok(monthWeeks.toEnd().isEqual(new DateTime([1970, 5, 3, 0, 0, 0, 0]))); 48 | }); 49 | 50 | test('[MonthWeeks] Create :: DateTime', function () { 51 | var dt = new DateTime([1970, 2, 15, 14, 0, 0, 0], UTC_TIMEZONE); 52 | 53 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 54 | 55 | monthWeeks = new MonthWeeks(dt); 56 | 57 | ok(monthWeeks.toStart() !== dt); 58 | ok(monthWeeks.toStart().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0])) === true); 59 | ok(monthWeeks.toEnd().isEqual(new DateTime([1970, 3, 1, 0, 0, 0, 0])) === true); 60 | 61 | // Original date shouldn't be altered 62 | ok(dt.isEqual(new DateTime([1970, 2, 15, 14, 0, 0, 0])) === true); 63 | }); 64 | 65 | test('[MonthWeeks] Create :: String', function () { 66 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 67 | 68 | monthWeeks = new MonthWeeks('1970-09-15'); 69 | 70 | ok(monthWeeks.toStart().isEqual(new DateTime([1970, 8, 30, 0, 0, 0, 0]))); 71 | ok(monthWeeks.toEnd().isEqual(new DateTime([1970, 10, 4, 0, 0, 0, 0]))); 72 | }); 73 | 74 | test('[MonthWeeks] Create :: Number', function () { 75 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 76 | 77 | monthWeeks = new MonthWeeks(914400000); 78 | 79 | ok(monthWeeks.toStart().isEqual(new DateTime([1969, 12, 28, 0, 0, 0, 0]))); 80 | ok(monthWeeks.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 81 | }); 82 | 83 | test('[MonthWeeks] Create :: String and timezone', function () { 84 | setTestTimezone({ 85 | abbr: [ 86 | 'TST', 87 | 'TST_1', 88 | 'TST' 89 | ], 90 | dst: [ 91 | false, 92 | true, 93 | false 94 | ], 95 | offset: [ 96 | 0, 97 | -60, // +0100 98 | 0 99 | ], 100 | until: [ 101 | 180000000, // 1970-01-03T02:00:00 102 | 262800000, // 1970-01-04T02:00:00 103 | null 104 | ] 105 | }); 106 | 107 | monthWeeks = new MonthWeeks('1970-01-03T03:00:00+0100', TEST_TIMEZONE); 108 | 109 | ok(monthWeeks.toStart().isEqual(new DateTime([1969, 12, 28, 0, 0, 0, 0], TEST_TIMEZONE))); 110 | ok(monthWeeks.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 111 | }); 112 | 113 | /** 114 | * ---------------------------------------------------------------------------------------- 115 | * Next monthWeeks 116 | * ---------------------------------------------------------------------------------------- 117 | */ 118 | 119 | test('[MonthWeeks] toNext', function () { 120 | monthWeeks = new MonthWeeks('1970-05-11T03:00:00', UTC_TIMEZONE); 121 | 122 | var nextMonthWeeks = monthWeeks.toNext(); 123 | 124 | ok(nextMonthWeeks !== monthWeeks); 125 | 126 | ok(nextMonthWeeks.toStart().isEqual(new DateTime([1970, 5, 31, 0, 0, 0, 0]))); 127 | ok(nextMonthWeeks.toEnd().isEqual(new DateTime([1970, 7, 5, 0, 0, 0, 0]))); 128 | 129 | // Original monthWeeks isn't altered 130 | ok(monthWeeks.toStart().isEqual(new DateTime([1970, 4, 26, 0, 0, 0, 0]))); 131 | ok(monthWeeks.toEnd().isEqual(new DateTime([1970, 6, 7, 0, 0, 0, 0]))); 132 | }); 133 | 134 | test('[MonthWeeks] toNext :: Next year', function () { 135 | monthWeeks = new MonthWeeks('1970-11-26T14:00:00', UTC_TIMEZONE); 136 | 137 | var nextMonthWeeks = monthWeeks.toNext(); 138 | 139 | ok(nextMonthWeeks.toStart().isEqual(new DateTime([1970, 11, 29, 0, 0, 0, 0]))); 140 | ok(nextMonthWeeks.toEnd().isEqual(new DateTime([1971, 1, 3, 0, 0, 0, 0]))); 141 | }); 142 | 143 | test('[MonthWeeks] toNext :: Timezone', function () { 144 | setTestTimezone({ 145 | abbr: [ 146 | 'TST', 147 | 'TST_1', 148 | 'TST' 149 | ], 150 | dst: [ 151 | false, 152 | true, 153 | false 154 | ], 155 | offset: [ 156 | 0, 157 | -60, // +0100 158 | 0 159 | ], 160 | until: [ 161 | 180000000, // 1970-01-03T02:00:00 162 | 262800000, // 1970-01-04T02:00:00 163 | null 164 | ] 165 | }); 166 | 167 | monthWeeks = new MonthWeeks('1970-01-02T14:00:00', TEST_TIMEZONE); 168 | 169 | var nextMonthWeeks = monthWeeks.toNext(); 170 | 171 | ok(nextMonthWeeks !== monthWeeks); 172 | 173 | ok(nextMonthWeeks.toStart().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 174 | ok(nextMonthWeeks.toEnd().isEqual(new DateTime([1970, 3, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 175 | }); 176 | 177 | /** 178 | * ---------------------------------------------------------------------------------------- 179 | * Previous monthWeeks 180 | * ---------------------------------------------------------------------------------------- 181 | */ 182 | 183 | test('[MonthWeeks] toPrev', function () { 184 | monthWeeks = new MonthWeeks('1970-05-15T03:00:00+0100', UTC_TIMEZONE); 185 | 186 | var prevMonthWeeks = monthWeeks.toPrev(); 187 | 188 | ok(prevMonthWeeks !== monthWeeks); 189 | 190 | ok(prevMonthWeeks.toStart().isEqual(new DateTime([1970, 3, 29, 0, 0, 0, 0]))); 191 | ok(prevMonthWeeks.toEnd().isEqual(new DateTime([1970, 5, 3, 0, 0, 0, 0]))); 192 | 193 | // Original monthWeeks isn't altered 194 | ok(monthWeeks.toStart().isEqual(new DateTime([1970, 4, 26, 0, 0, 0, 0]))); 195 | ok(monthWeeks.toEnd().isEqual(new DateTime([1970, 6, 7, 0, 0, 0, 0]))); 196 | }); 197 | 198 | test('[MonthWeeks] toPrev :: Previous year', function () { 199 | monthWeeks = new MonthWeeks('1970-02-15T00:30:00', UTC_TIMEZONE); 200 | 201 | var prevMonthWeeks = monthWeeks.toPrev(); 202 | 203 | ok(prevMonthWeeks.toStart().isEqual(new DateTime([1969, 12, 28, 0, 0, 0, 0]))); 204 | ok(prevMonthWeeks.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 205 | }); 206 | 207 | test('[MonthWeeks] toPrev :: Timezone', function () { 208 | setTestTimezone({ 209 | abbr: [ 210 | 'TST', 211 | 'TST_1', 212 | 'TST' 213 | ], 214 | dst: [ 215 | false, 216 | true, 217 | false 218 | ], 219 | offset: [ 220 | 0, 221 | -60, // +0100 222 | 0 223 | ], 224 | until: [ 225 | 180000000, // 1970-01-03T02:00:00 226 | 262800000, // 1970-01-04T02:00:00 227 | null 228 | ] 229 | }); 230 | 231 | monthWeeks = new MonthWeeks('1970-01-03T03:00:00+0100', TEST_TIMEZONE); 232 | 233 | var prevMonthWeeks = monthWeeks.toPrev(); 234 | 235 | ok(prevMonthWeeks !== monthWeeks); 236 | 237 | ok(prevMonthWeeks.toStart().isEqual(new DateTime([1969, 11, 30, 0, 0, 0, 0], TEST_TIMEZONE))); 238 | ok(prevMonthWeeks.toEnd().isEqual(new DateTime([1970, 1, 4, 0, 0, 0, 0], TEST_TIMEZONE))); 239 | }); 240 | 241 | /** 242 | * ---------------------------------------------------------------------------------------- 243 | * toWeeks 244 | * ---------------------------------------------------------------------------------------- 245 | */ 246 | 247 | test('[MonthWeeks] toWeeks :: 4 weeks', function () { 248 | monthWeeks = new MonthWeeks('2015-02-01', UTC_TIMEZONE); 249 | weeks = monthWeeks.toWeeks(); 250 | 251 | ok(weeks.length === 4); 252 | 253 | ok(weeks[0].toStart().isEqual(new DateTime([2015, 2, 1, 0, 0, 0, 0], UTC_TIMEZONE))); 254 | ok(weeks[0].toEnd().isEqual(new DateTime([2015, 2, 8, 0, 0, 0, 0], UTC_TIMEZONE))); 255 | 256 | ok(weeks[1].toStart().isEqual(new DateTime([2015, 2, 8, 0, 0, 0, 0], UTC_TIMEZONE))); 257 | ok(weeks[1].toEnd().isEqual(new DateTime([2015, 2, 15, 0, 0, 0, 0], UTC_TIMEZONE))); 258 | 259 | ok(weeks[2].toStart().isEqual(new DateTime([2015, 2, 15, 0, 0, 0, 0], UTC_TIMEZONE))); 260 | ok(weeks[2].toEnd().isEqual(new DateTime([2015, 2, 22, 0, 0, 0, 0], UTC_TIMEZONE))); 261 | 262 | ok(weeks[3].toStart().isEqual(new DateTime([2015, 2, 22, 0, 0, 0, 0], UTC_TIMEZONE))); 263 | ok(weeks[3].toEnd().isEqual(new DateTime([2015, 2, 29, 0, 0, 0, 0], UTC_TIMEZONE))); 264 | }); 265 | 266 | test('[MonthWeeks] toWeeks :: 5 weeks', function () { 267 | monthWeeks = new MonthWeeks('2017-01-01', UTC_TIMEZONE); 268 | weeks = monthWeeks.toWeeks(); 269 | 270 | ok(weeks.length === 5); 271 | 272 | ok(weeks[0].toStart().isEqual(new DateTime([2017, 1, 1, 0, 0, 0, 0], UTC_TIMEZONE))); 273 | ok(weeks[0].toEnd().isEqual(new DateTime([2017, 1, 8, 0, 0, 0, 0], UTC_TIMEZONE))); 274 | 275 | ok(weeks[1].toStart().isEqual(new DateTime([2017, 1, 8, 0, 0, 0, 0], UTC_TIMEZONE))); 276 | ok(weeks[1].toEnd().isEqual(new DateTime([2017, 1, 15, 0, 0, 0, 0], UTC_TIMEZONE))); 277 | 278 | ok(weeks[2].toStart().isEqual(new DateTime([2017, 1, 15, 0, 0, 0, 0], UTC_TIMEZONE))); 279 | ok(weeks[2].toEnd().isEqual(new DateTime([2017, 1, 22, 0, 0, 0, 0], UTC_TIMEZONE))); 280 | 281 | ok(weeks[3].toStart().isEqual(new DateTime([2017, 1, 22, 0, 0, 0, 0], UTC_TIMEZONE))); 282 | ok(weeks[3].toEnd().isEqual(new DateTime([2017, 1, 29, 0, 0, 0, 0], UTC_TIMEZONE))); 283 | 284 | ok(weeks[4].toStart().isEqual(new DateTime([2017, 1, 29, 0, 0, 0, 0], UTC_TIMEZONE))); 285 | ok(weeks[4].toEnd().isEqual(new DateTime([2017, 2, 5, 0, 0, 0, 0], UTC_TIMEZONE))); 286 | }); 287 | 288 | test('[MonthWeeks] toWeeks :: 6 weeks', function () { 289 | monthWeeks = new MonthWeeks('2017-04-01', UTC_TIMEZONE); 290 | weeks = monthWeeks.toWeeks(); 291 | 292 | ok(weeks.length === 6); 293 | 294 | ok(weeks[0].toStart().isEqual(new DateTime([2017, 3, 26, 0, 0, 0, 0], UTC_TIMEZONE))); 295 | ok(weeks[0].toEnd().isEqual(new DateTime([2017, 4, 2, 0, 0, 0, 0], UTC_TIMEZONE))); 296 | 297 | ok(weeks[1].toStart().isEqual(new DateTime([2017, 4, 2, 0, 0, 0, 0], UTC_TIMEZONE))); 298 | ok(weeks[1].toEnd().isEqual(new DateTime([2017, 4, 9, 0, 0, 0, 0], UTC_TIMEZONE))); 299 | 300 | ok(weeks[2].toStart().isEqual(new DateTime([2017, 4, 9, 0, 0, 0, 0], UTC_TIMEZONE))); 301 | ok(weeks[2].toEnd().isEqual(new DateTime([2017, 4, 16, 0, 0, 0, 0], UTC_TIMEZONE))); 302 | 303 | ok(weeks[3].toStart().isEqual(new DateTime([2017, 4, 16, 0, 0, 0, 0], UTC_TIMEZONE))); 304 | ok(weeks[3].toEnd().isEqual(new DateTime([2017, 4, 23, 0, 0, 0, 0], UTC_TIMEZONE))); 305 | 306 | ok(weeks[4].toStart().isEqual(new DateTime([2017, 4, 23, 0, 0, 0, 0], UTC_TIMEZONE))); 307 | ok(weeks[4].toEnd().isEqual(new DateTime([2017, 4, 30, 0, 0, 0, 0], UTC_TIMEZONE))); 308 | 309 | ok(weeks[5].toStart().isEqual(new DateTime([2017, 4, 30, 0, 0, 0, 0], UTC_TIMEZONE))); 310 | ok(weeks[5].toEnd().isEqual(new DateTime([2017, 5, 7, 0, 0, 0, 0], UTC_TIMEZONE))); 311 | }); 312 | 313 | test('[MonthWeeks] toWeeks :: Timezone', function () { 314 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 315 | 316 | setTestTimezone({ 317 | abbr: [ 318 | 'TST', 319 | 'TST_1' 320 | ], 321 | dst: [ 322 | false, 323 | true 324 | ], 325 | offset: [ 326 | 0, 327 | -60 // +0100 328 | ], 329 | until: [ 330 | 180000000, // 1970-01-03T02:00:00 331 | null 332 | ] 333 | }); 334 | 335 | monthWeeks = new MonthWeeks('2017-01-01', TEST_TIMEZONE); 336 | weeks = monthWeeks.toWeeks(); 337 | 338 | ok(weeks.length === 5); 339 | 340 | ok(weeks[0].toStart().isEqual(new DateTime([2017, 1, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 341 | ok(weeks[0].toEnd().isEqual(new DateTime([2017, 1, 8, 0, 0, 0, 0], TEST_TIMEZONE))); 342 | 343 | ok(weeks[1].toStart().isEqual(new DateTime([2017, 1, 8, 0, 0, 0, 0], TEST_TIMEZONE))); 344 | ok(weeks[1].toEnd().isEqual(new DateTime([2017, 1, 15, 0, 0, 0, 0], TEST_TIMEZONE))); 345 | 346 | ok(weeks[2].toStart().isEqual(new DateTime([2017, 1, 15, 0, 0, 0, 0], TEST_TIMEZONE))); 347 | ok(weeks[2].toEnd().isEqual(new DateTime([2017, 1, 22, 0, 0, 0, 0], TEST_TIMEZONE))); 348 | 349 | ok(weeks[3].toStart().isEqual(new DateTime([2017, 1, 22, 0, 0, 0, 0], TEST_TIMEZONE))); 350 | ok(weeks[3].toEnd().isEqual(new DateTime([2017, 1, 29, 0, 0, 0, 0], TEST_TIMEZONE))); 351 | 352 | ok(weeks[4].toStart().isEqual(new DateTime([2017, 1, 29, 0, 0, 0, 0], TEST_TIMEZONE))); 353 | ok(weeks[4].toEnd().isEqual(new DateTime([2017, 2, 5, 0, 0, 0, 0], TEST_TIMEZONE))); 354 | }); 355 | 356 | /** 357 | * ---------------------------------------------------------------------------------------- 358 | * Display 359 | * ---------------------------------------------------------------------------------------- 360 | */ 361 | 362 | test('[MonthWeeks] Display :: format', function () { 363 | monthWeeks = new MonthWeeks('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 364 | ok(monthWeeks.format('YYYY-MM-DD') === '1969-12-28 – 1970-02-01'); 365 | }); 366 | 367 | test('[MonthWeeks] Display :: toISOString', function () { 368 | monthWeeks = new MonthWeeks('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 369 | ok(monthWeeks.toISOString() === '1969-12-28T00:00:00.000Z – 1970-02-01T00:00:00.000Z'); 370 | }); 371 | 372 | test('[MonthWeeks] Display :: toLocaleString', function () { 373 | monthWeeks = new MonthWeeks('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 374 | ok(monthWeeks.toLocaleString() === '12/28/1969, 12:00:00 AM – 2/1/1970, 12:00:00 AM'); 375 | }); 376 | 377 | test('[MonthWeeks] Display :: toString', function () { 378 | monthWeeks = new MonthWeeks('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 379 | ok(monthWeeks.toString() === 'Sun Dec 28 1969 00:00:00 GMT+0000 (UTC) – Sun Feb 01 1970 00:00:00 GMT+0000 (UTC)'); 380 | }); 381 | 382 | test('[MonthWeeks] Display :: toUTCString', function () { 383 | monthWeeks = new MonthWeeks('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 384 | ok(monthWeeks.toUTCString() === 'Sun, 28 Dec 1969 00:00:00 GMT – Sun, 01 Feb 1970 00:00:00 GMT'); 385 | }); 386 | 387 | /** 388 | * ---------------------------------------------------------------------------------------- 389 | * Other methods 390 | * ---------------------------------------------------------------------------------------- 391 | */ 392 | 393 | test('[MonthWeeks] toJSON', function () { 394 | monthWeeks = new MonthWeeks('2016-05-01T14:30:00', UTC_TIMEZONE); 395 | ok(monthWeeks.toJSON() === 'Sun May 01 2016 00:00:00 GMT+0000 (UTC) – Sun Jun 05 2016 00:00:00 GMT+0000 (UTC)'); 396 | }); 397 | 398 | test('[MonthWeeks] valueOf', function () { 399 | setTestTimezone({ 400 | abbr: [ 401 | 'TST', 402 | 'TST_1' 403 | ], 404 | dst: [ 405 | false, 406 | true 407 | ], 408 | offset: [ 409 | 0, 410 | -60 // +0100 411 | ], 412 | until: [ 413 | 180000000, // 1970-01-03T02:00:00 414 | null 415 | ] 416 | }); 417 | 418 | monthWeeks = new MonthWeeks('2016-04-01', UTC_TIMEZONE); 419 | ok(monthWeeks.valueOf() === 3024000000); 420 | 421 | monthWeeks = new MonthWeeks('2016-01-01', UTC_TIMEZONE); 422 | ok(monthWeeks.valueOf() === 3628800000); 423 | 424 | monthWeeks = new MonthWeeks('1970-01-03', TEST_TIMEZONE); 425 | ok(monthWeeks.valueOf() === 3020400000); 426 | }); 427 | })(); 428 | -------------------------------------------------------------------------------- /test/unit/spec/calendar/month.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var UTC_TIMEZONE = 'UTC'; 11 | 12 | var test = createTestFn(); 13 | 14 | var Month = DateTime.Month; 15 | var Interval = DateTime.Interval; 16 | 17 | /** 18 | * ---------------------------------------------------------------------------------------- 19 | * Class 20 | * ---------------------------------------------------------------------------------------- 21 | */ 22 | 23 | test('[Month] Class', function () { 24 | ok(typeof Month === 'function'); 25 | }); 26 | 27 | /** 28 | * ---------------------------------------------------------------------------------------- 29 | * Create 30 | * ---------------------------------------------------------------------------------------- 31 | */ 32 | 33 | test('[Month] Create :: No arguments', function () { 34 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 35 | 36 | mockNow(864000000); 37 | 38 | var month = new Month(); 39 | 40 | ok(month instanceof Month); 41 | ok(month instanceof Interval); 42 | 43 | ok(month.toStart().isEqual(new DateTime([1970, 1, 1, 0, 0, 0, 0]))); 44 | ok(month.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 45 | }); 46 | 47 | test('[Month] Create :: DateTime', function () { 48 | var dt = new DateTime([1970, 1, 11, 14, 0, 0, 0], UTC_TIMEZONE); 49 | 50 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 51 | 52 | var month = new Month(dt); 53 | 54 | ok(month.toStart() !== dt); 55 | ok(month.toStart().isEqual(new DateTime([1970, 1, 1, 0, 0, 0, 0])) === true); 56 | ok(month.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0])) === true); 57 | 58 | // Original date shouldn't be altered 59 | ok(dt.isEqual(new DateTime([1970, 1, 11, 14, 0, 0, 0])) === true); 60 | }); 61 | 62 | test('[Month] Create :: String', function () { 63 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 64 | 65 | var month = new Month('1970-02-11'); 66 | 67 | ok(month.toStart().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 68 | ok(month.toEnd().isEqual(new DateTime([1970, 3, 1, 0, 0, 0, 0]))); 69 | }); 70 | 71 | test('[Month] Create :: Number', function () { 72 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 73 | 74 | var month = new Month(914400000); 75 | 76 | ok(month.toStart().isEqual(new DateTime([1970, 1, 1, 0, 0, 0, 0]))); 77 | ok(month.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 78 | }); 79 | 80 | test('[Month] Create :: String and timezone', function () { 81 | setTestTimezone({ 82 | abbr: [ 83 | 'TST', 84 | 'TST_1', 85 | 'TST' 86 | ], 87 | dst: [ 88 | false, 89 | true, 90 | false 91 | ], 92 | offset: [ 93 | 0, 94 | -60, // +0100 95 | 0 96 | ], 97 | until: [ 98 | 180000000, // 1970-01-03T02:00:00 99 | 262800000, // 1970-01-04T02:00:00 100 | null 101 | ] 102 | }); 103 | 104 | var month = new Month('1970-01-03T03:00:00+0100', TEST_TIMEZONE); 105 | 106 | ok(month.toStart().isEqual(new DateTime([1970, 1, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 107 | ok(month.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 108 | }); 109 | 110 | /** 111 | * ---------------------------------------------------------------------------------------- 112 | * Getters 113 | * ---------------------------------------------------------------------------------------- 114 | */ 115 | 116 | test('[Month] getMonth', function () { 117 | var month = new Month('1979-05', UTC_TIMEZONE); 118 | ok(month.getMonth() === 5); 119 | }); 120 | 121 | test('[Month] getYear', function () { 122 | var month = new Month('1979-01', UTC_TIMEZONE); 123 | ok(month.getYear() === 1979); 124 | }); 125 | 126 | /** 127 | * ---------------------------------------------------------------------------------------- 128 | * Next month 129 | * ---------------------------------------------------------------------------------------- 130 | */ 131 | 132 | test('[Month] toNext', function () { 133 | var month = new Month('1970-01-11T03:00:00', UTC_TIMEZONE); 134 | var nextMonth = month.toNext(); 135 | 136 | ok(nextMonth !== month); 137 | 138 | ok(nextMonth.toStart().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 139 | ok(nextMonth.toEnd().isEqual(new DateTime([1970, 3, 1, 0, 0, 0, 0]))); 140 | 141 | // Original month isn't altered 142 | ok(month.toStart().isEqual(new DateTime([1970, 1, 1, 0, 0, 0, 0]))); 143 | ok(month.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 144 | }); 145 | 146 | test('[Month] toNext :: Next year', function () { 147 | var month = new Month('1970-11-26T14:00:00', UTC_TIMEZONE); 148 | var nextMonth = month.toNext(); 149 | 150 | ok(nextMonth.toStart().isEqual(new DateTime([1970, 12, 1, 0, 0, 0, 0]))); 151 | ok(nextMonth.toEnd().isEqual(new DateTime([1971, 1, 1, 0, 0, 0, 0]))); 152 | }); 153 | 154 | test('[Month] toNext :: Timezone', function () { 155 | setTestTimezone({ 156 | abbr: [ 157 | 'TST', 158 | 'TST_1', 159 | 'TST' 160 | ], 161 | dst: [ 162 | false, 163 | true, 164 | false 165 | ], 166 | offset: [ 167 | 0, 168 | -60, // +0100 169 | 0 170 | ], 171 | until: [ 172 | 180000000, // 1970-01-03T02:00:00 173 | 262800000, // 1970-01-04T02:00:00 174 | null 175 | ] 176 | }); 177 | 178 | var month = new Month('1970-01-02T14:00:00', TEST_TIMEZONE); 179 | var nextMonth = month.toNext(); 180 | 181 | ok(nextMonth !== month); 182 | 183 | ok(nextMonth.toStart().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 184 | ok(nextMonth.toEnd().isEqual(new DateTime([1970, 3, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 185 | }); 186 | 187 | /** 188 | * ---------------------------------------------------------------------------------------- 189 | * Previous month 190 | * ---------------------------------------------------------------------------------------- 191 | */ 192 | 193 | test('[Month] toPrev', function () { 194 | var month = new Month('1970-05-15T03:00:00+0100', UTC_TIMEZONE); 195 | var prevMonth = month.toPrev(); 196 | 197 | ok(prevMonth !== month); 198 | 199 | ok(prevMonth.toStart().isEqual(new DateTime([1970, 4, 1, 0, 0, 0, 0]))); 200 | ok(prevMonth.toEnd().isEqual(new DateTime([1970, 5, 1, 0, 0, 0, 0]))); 201 | 202 | // Original month isn't altered 203 | ok(month.toStart().isEqual(new DateTime([1970, 5, 1, 0, 0, 0, 0]))); 204 | ok(month.toEnd().isEqual(new DateTime([1970, 6, 1, 0, 0, 0, 0]))); 205 | }); 206 | 207 | test('[Month] toPrev :: Previous year', function () { 208 | var month = new Month('1970-01-05T00:30:00', UTC_TIMEZONE); 209 | var prevMonth = month.toPrev(); 210 | 211 | ok(prevMonth.toStart().isEqual(new DateTime([1969, 12, 1, 0, 0, 0, 0]))); 212 | ok(prevMonth.toEnd().isEqual(new DateTime([1970, 1, 1, 0, 0, 0, 0]))); 213 | }); 214 | 215 | test('[Month] toPrev :: Timezone', function () { 216 | setTestTimezone({ 217 | abbr: [ 218 | 'TST', 219 | 'TST_1', 220 | 'TST' 221 | ], 222 | dst: [ 223 | false, 224 | true, 225 | false 226 | ], 227 | offset: [ 228 | 0, 229 | -60, // +0100 230 | 0 231 | ], 232 | until: [ 233 | 180000000, // 1970-01-03T02:00:00 234 | 262800000, // 1970-01-04T02:00:00 235 | null 236 | ] 237 | }); 238 | 239 | var month = new Month('1970-01-03T03:00:00+0100', TEST_TIMEZONE); 240 | var prevMonth = month.toPrev(); 241 | 242 | ok(prevMonth !== month); 243 | 244 | ok(prevMonth.toStart().isEqual(new DateTime([1969, 12, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 245 | ok(prevMonth.toEnd().isEqual(new DateTime([1970, 1, 1, 0, 0, 0, 0], TEST_TIMEZONE))); 246 | }); 247 | 248 | /** 249 | * ---------------------------------------------------------------------------------------- 250 | * toDays 251 | * ---------------------------------------------------------------------------------------- 252 | */ 253 | 254 | test('[Month] toDays :: 31 days', function () { 255 | var month = new Month('2017-05-15', UTC_TIMEZONE); 256 | var days = month.toDays(); 257 | 258 | ok(days.length === 31); 259 | 260 | var idx = days.length; 261 | while (idx--) { 262 | ok(days[idx].toStart().isEqual(new DateTime([2017, 5, idx + 1, 0, 0, 0, 0], UTC_TIMEZONE))); 263 | ok(days[idx].toEnd().isEqual(new DateTime([2017, 5, idx + 2, 0, 0, 0, 0], UTC_TIMEZONE))); 264 | } 265 | }); 266 | 267 | test('[Month] toDays :: 30 days', function () { 268 | var month = new Month('2017-04-15', UTC_TIMEZONE); 269 | var days = month.toDays(); 270 | 271 | ok(days.length === 30); 272 | 273 | var idx = days.length; 274 | while (idx--) { 275 | ok(days[idx].toStart().isEqual(new DateTime([2017, 4, idx + 1, 0, 0, 0, 0], UTC_TIMEZONE))); 276 | ok(days[idx].toEnd().isEqual(new DateTime([2017, 4, idx + 2, 0, 0, 0, 0], UTC_TIMEZONE))); 277 | } 278 | }); 279 | 280 | test('[Month] toDays :: 29 days', function () { 281 | var month = new Month('2016-02-15', UTC_TIMEZONE); 282 | var days = month.toDays(); 283 | 284 | ok(days.length === 29); 285 | 286 | var idx = days.length; 287 | while (idx--) { 288 | ok(days[idx].toStart().isEqual(new DateTime([2016, 2, idx + 1, 0, 0, 0, 0], UTC_TIMEZONE))); 289 | ok(days[idx].toEnd().isEqual(new DateTime([2016, 2, idx + 2, 0, 0, 0, 0], UTC_TIMEZONE))); 290 | } 291 | }); 292 | 293 | test('[Month] toDays :: 28 days', function () { 294 | var month = new Month('2015-02-15', UTC_TIMEZONE); 295 | var days = month.toDays(); 296 | 297 | ok(days.length === 28); 298 | 299 | var idx = days.length; 300 | while (idx--) { 301 | ok(days[idx].toStart().isEqual(new DateTime([2015, 2, idx + 1, 0, 0, 0, 0], UTC_TIMEZONE))); 302 | ok(days[idx].toEnd().isEqual(new DateTime([2015, 2, idx + 2, 0, 0, 0, 0], UTC_TIMEZONE))); 303 | } 304 | }); 305 | 306 | test('[Month] toDays :: Timezone', function () { 307 | setTestTimezone({ 308 | abbr: [ 309 | 'TST', 310 | 'TST_1' 311 | ], 312 | dst: [ 313 | false, 314 | true 315 | ], 316 | offset: [ 317 | 0, 318 | -60 // +0100 319 | ], 320 | until: [ 321 | 180000000, // 1970-01-03T02:00:00 322 | null 323 | ] 324 | }); 325 | 326 | var month = new Month('2017-05-15', TEST_TIMEZONE); 327 | var days = month.toDays(); 328 | 329 | ok(days.length === 31); 330 | 331 | var idx = days.length; 332 | while (idx--) { 333 | ok(days[idx].toStart().isEqual(new DateTime([2017, 5, idx + 1, 0, 0, 0, 0], TEST_TIMEZONE))); 334 | ok(days[idx].toEnd().isEqual(new DateTime([2017, 5, idx + 2, 0, 0, 0, 0], TEST_TIMEZONE))); 335 | } 336 | }); 337 | 338 | /** 339 | * ---------------------------------------------------------------------------------------- 340 | * Display 341 | * ---------------------------------------------------------------------------------------- 342 | */ 343 | 344 | test('[Month] Display :: format', function () { 345 | var month = new Month('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 346 | ok(month.format('YYYY-MM-DD') === '1970-01-01 – 1970-02-01'); 347 | }); 348 | 349 | test('[Month] Display :: toISOString', function () { 350 | var month = new Month('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 351 | ok(month.toISOString() === '1970-01-01T00:00:00.000Z – 1970-02-01T00:00:00.000Z'); 352 | }); 353 | 354 | test('[Month] Display :: toLocaleString', function () { 355 | var month = new Month('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 356 | ok(month.toLocaleString() === '1/1/1970, 12:00:00 AM – 2/1/1970, 12:00:00 AM'); 357 | }); 358 | 359 | test('[Month] Display :: toString', function () { 360 | var month = new Month('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 361 | ok(month.toString() === 'Thu Jan 01 1970 00:00:00 GMT+0000 (UTC) – Sun Feb 01 1970 00:00:00 GMT+0000 (UTC)'); 362 | }); 363 | 364 | test('[Month] Display :: toUTCString', function () { 365 | var month = new Month('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 366 | ok(month.toUTCString() === 'Thu, 01 Jan 1970 00:00:00 GMT – Sun, 01 Feb 1970 00:00:00 GMT'); 367 | }); 368 | 369 | /** 370 | * ---------------------------------------------------------------------------------------- 371 | * Other methods 372 | * ---------------------------------------------------------------------------------------- 373 | */ 374 | 375 | test('[Month] toJSON', function () { 376 | var month = new Month('2016-05-01T14:30:00', UTC_TIMEZONE); 377 | ok(month.toJSON() === 'Sun May 01 2016 00:00:00 GMT+0000 (UTC) – Wed Jun 01 2016 00:00:00 GMT+0000 (UTC)'); 378 | }); 379 | 380 | test('[Month] valueOf', function () { 381 | setTestTimezone({ 382 | abbr: [ 383 | 'TST', 384 | 'TST_1' 385 | ], 386 | dst: [ 387 | false, 388 | true 389 | ], 390 | offset: [ 391 | 0, 392 | -60 // +0100 393 | ], 394 | until: [ 395 | 180000000, // 1970-01-03T02:00:00 396 | null 397 | ] 398 | }); 399 | 400 | var month = new Month('2016-04-01', UTC_TIMEZONE); 401 | ok(month.valueOf() === 2592000000); 402 | 403 | month = new Month('2016-01-01', UTC_TIMEZONE); 404 | ok(month.valueOf() === 2678400000); 405 | 406 | month = new Month('2016-02-05', UTC_TIMEZONE); 407 | ok(month.valueOf() === 2505600000); 408 | 409 | month = new Month('2017-02-05', UTC_TIMEZONE); 410 | ok(month.valueOf() === 2419200000); 411 | 412 | month = new Month('1970-01-03', TEST_TIMEZONE); 413 | ok(month.valueOf() === 2674800000); 414 | }); 415 | })(); 416 | -------------------------------------------------------------------------------- /test/unit/spec/calendar/second.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var UTC_TIMEZONE = 'UTC'; 11 | 12 | var test = createTestFn(); 13 | 14 | var Second = DateTime.Second; 15 | var Interval = DateTime.Interval; 16 | 17 | /** 18 | * ---------------------------------------------------------------------------------------- 19 | * Class 20 | * ---------------------------------------------------------------------------------------- 21 | */ 22 | 23 | test('[Second] Class', function () { 24 | ok(typeof Second === 'function'); 25 | }); 26 | 27 | /** 28 | * ---------------------------------------------------------------------------------------- 29 | * Create 30 | * ---------------------------------------------------------------------------------------- 31 | */ 32 | 33 | test('[Second] Create :: No arguments', function () { 34 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 35 | 36 | mockNow(880235400); 37 | 38 | var second = new Second(); 39 | 40 | ok(second instanceof Second); 41 | ok(second instanceof Interval); 42 | 43 | ok(second.toStart().isEqual(new DateTime([1970, 1, 11, 4, 30, 35, 0]))); 44 | ok(second.toEnd().isEqual(new DateTime([1970, 1, 11, 4, 30, 36, 0]))); 45 | }); 46 | 47 | test('[Second] Create :: DateTime', function () { 48 | var dt = new DateTime([1970, 1, 11, 14, 25, 15, 555], UTC_TIMEZONE); 49 | 50 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 51 | 52 | var second = new Second(dt); 53 | 54 | ok(second.toStart() !== dt); 55 | ok(second.toStart().isEqual(new DateTime([1970, 1, 11, 14, 25, 15, 0])) === true); 56 | ok(second.toEnd().isEqual(new DateTime([1970, 1, 11, 14, 25, 16, 0])) === true); 57 | 58 | // Original date shouldn't be altered 59 | ok(dt.isEqual(new DateTime([1970, 1, 11, 14, 25, 15, 555])) === true); 60 | }); 61 | 62 | test('[Second] Create :: String', function () { 63 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 64 | 65 | var second = new Second('1970-01-11'); 66 | 67 | ok(second.toStart().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0]))); 68 | ok(second.toEnd().isEqual(new DateTime([1970, 1, 11, 0, 0, 1, 0]))); 69 | }); 70 | 71 | test('[Second] Create :: Number', function () { 72 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 73 | 74 | var second = new Second(914423100); 75 | 76 | ok(second.toStart().isEqual(new DateTime([1970, 1, 11, 14, 0, 23, 0]))); 77 | ok(second.toEnd().isEqual(new DateTime([1970, 1, 11, 14, 0, 24, 0]))); 78 | }); 79 | 80 | test('[Second] Create :: String and timezone', function () { 81 | setTestTimezone({ 82 | abbr: [ 83 | 'TST', 84 | 'TST_1', 85 | 'TST' 86 | ], 87 | dst: [ 88 | false, 89 | true, 90 | false 91 | ], 92 | offset: [ 93 | 0, 94 | -60, // +0100 95 | 0 96 | ], 97 | until: [ 98 | 180000000, // 1970-01-03T02:00:00 99 | 262800000, // 1970-01-04T02:00:00 100 | null 101 | ] 102 | }); 103 | 104 | var second = new Second('1970-01-03T03:27:59+0100', TEST_TIMEZONE); 105 | 106 | ok(second.toStart().isEqual(new DateTime([1970, 1, 3, 3, 27, 59, 0], TEST_TIMEZONE))); 107 | ok(second.toEnd().isEqual(new DateTime([1970, 1, 3, 3, 28, 0, 0], TEST_TIMEZONE))); 108 | }); 109 | 110 | /** 111 | * ---------------------------------------------------------------------------------------- 112 | * Getters 113 | * ---------------------------------------------------------------------------------------- 114 | */ 115 | 116 | test('[Second] getSecond', function () { 117 | var second = new Second('1979-05-03T11:55:44+0100', UTC_TIMEZONE); 118 | ok(second.getSecond() === 44); 119 | }); 120 | 121 | test('[Second] getMinute', function () { 122 | var second = new Second('1979-05-03T11:55:44+0100', UTC_TIMEZONE); 123 | ok(second.getMinute() === 55); 124 | }); 125 | 126 | test('[Second] getHour', function () { 127 | var second = new Second('1979-05-03T11:00:44+0100', UTC_TIMEZONE); 128 | ok(second.getHour() === 10); 129 | }); 130 | 131 | test('[Second] getDayOfWeek', function () { 132 | var second; 133 | 134 | second = new Second('1979-04-29T03:00:44+0100', UTC_TIMEZONE); 135 | ok(second.getDayOfWeek() === 0); 136 | 137 | second = new Second('1979-05-05T03:00:44+0100', UTC_TIMEZONE); 138 | ok(second.getDayOfWeek() === 6); 139 | }); 140 | 141 | test('[Second] getDayOfMonth', function () { 142 | var second = new Second('1979-05-03T03:00:44+0100', UTC_TIMEZONE); 143 | ok(second.getDayOfMonth() === 3); 144 | }); 145 | 146 | test('[Second] getMonth', function () { 147 | var second = new Second('1979-05-03T03:00:44+0100', UTC_TIMEZONE); 148 | ok(second.getMonth() === 5); 149 | }); 150 | 151 | test('[Second] getYear', function () { 152 | var second = new Second('1979-01-03T03:00:44+0100', UTC_TIMEZONE); 153 | ok(second.getYear() === 1979); 154 | }); 155 | 156 | /** 157 | * ---------------------------------------------------------------------------------------- 158 | * Next second 159 | * ---------------------------------------------------------------------------------------- 160 | */ 161 | 162 | test('[Second] toNext', function () { 163 | var second = new Second('1970-01-03T03:59:59.125', UTC_TIMEZONE); 164 | var nextSecond = second.toNext(); 165 | 166 | ok(nextSecond !== second); 167 | 168 | ok(nextSecond.toStart().isEqual(new DateTime([1970, 1, 3, 4, 0, 0, 0]))); 169 | ok(nextSecond.toEnd().isEqual(new DateTime([1970, 1, 3, 4, 0, 1, 0]))); 170 | 171 | // Original second isn't altered 172 | ok(second.toStart().isEqual(new DateTime([1970, 1, 3, 3, 59, 59, 0]))); 173 | ok(second.toEnd().isEqual(new DateTime([1970, 1, 3, 4, 0, 0, 0]))); 174 | }); 175 | 176 | test('[Second] toNext :: Next month', function () { 177 | var second = new Second('1970-01-31T23:59:58', UTC_TIMEZONE); 178 | var nextSecond = second.toNext(); 179 | 180 | ok(nextSecond.toStart().isEqual(new DateTime([1970, 1, 31, 23, 59, 59, 0]))); 181 | ok(nextSecond.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 182 | }); 183 | 184 | test('[Second] toNext :: Next year', function () { 185 | var second = new Second('2016-12-31T23:59:58', UTC_TIMEZONE); 186 | var nextSecond = second.toNext(); 187 | 188 | ok(nextSecond.toStart().isEqual(new DateTime([2016, 12, 31, 23, 59, 59, 0]))); 189 | ok(nextSecond.toEnd().isEqual(new DateTime([2017, 1, 1, 0, 0, 0, 0]))); 190 | }); 191 | 192 | test('[Second] toNext :: Timezone', function () { 193 | setTestTimezone({ 194 | abbr: [ 195 | 'TST', 196 | 'TST_1', 197 | 'TST' 198 | ], 199 | dst: [ 200 | false, 201 | true, 202 | false 203 | ], 204 | offset: [ 205 | 0, 206 | -60, // +0100 207 | 0 208 | ], 209 | until: [ 210 | 180000000, // 1970-01-03T02:00:00 211 | 262800000, // 1970-01-04T02:00:00 212 | null 213 | ] 214 | }); 215 | 216 | var second = new Second('1970-01-03T00:30:45', TEST_TIMEZONE); 217 | var nextSecond = second.toNext(); 218 | 219 | ok(nextSecond !== second); 220 | 221 | ok(nextSecond.toStart().isEqual(new DateTime([1970, 1, 3, 0, 30, 46, 0], TEST_TIMEZONE))); 222 | ok(nextSecond.toEnd().isEqual(new DateTime([1970, 1, 3, 0, 30, 47, 0], TEST_TIMEZONE))); 223 | }); 224 | 225 | /** 226 | * ---------------------------------------------------------------------------------------- 227 | * Previous second 228 | * ---------------------------------------------------------------------------------------- 229 | */ 230 | 231 | test('[Second] toPrev', function () { 232 | var second = new Second('1970-01-03T03:00:00', UTC_TIMEZONE); 233 | var prevSecond = second.toPrev(); 234 | 235 | ok(prevSecond !== second); 236 | 237 | ok(prevSecond.toStart().isEqual(new DateTime([1970, 1, 3, 2, 59, 59, 0]))); 238 | ok(prevSecond.toEnd().isEqual(new DateTime([1970, 1, 3, 3, 0, 0, 0]))); 239 | 240 | // Original second isn't altered 241 | ok(second.toStart().isEqual(new DateTime([1970, 1, 3, 3, 0, 0, 0]))); 242 | ok(second.toEnd().isEqual(new DateTime([1970, 1, 3, 3, 0, 1, 0]))); 243 | }); 244 | 245 | test('[Second] toPrev :: Previous month', function () { 246 | var second = new Second('1970-02-01T00:00:00.999', UTC_TIMEZONE); 247 | var prevSecond = second.toPrev(); 248 | 249 | ok(prevSecond.toStart().isEqual(new DateTime([1970, 1, 31, 23, 59, 59, 0]))); 250 | ok(prevSecond.toEnd().isEqual(new DateTime([1970, 2, 1, 0, 0, 0, 0]))); 251 | }); 252 | 253 | test('[Second] toPrev :: Previous year', function () { 254 | var second = new Second('2017-01-01T00:00:00', UTC_TIMEZONE); 255 | var prevSecond = second.toPrev(); 256 | 257 | ok(prevSecond.toStart().isEqual(new DateTime([2016, 12, 31, 23, 59, 59, 0]))); 258 | ok(prevSecond.toEnd().isEqual(new DateTime([2017, 1, 1, 0, 0, 0, 0]))); 259 | }); 260 | 261 | test('[Second] toPrev :: Timezone', function () { 262 | setTestTimezone({ 263 | abbr: [ 264 | 'TST', 265 | 'TST_1', 266 | 'TST' 267 | ], 268 | dst: [ 269 | false, 270 | true, 271 | false 272 | ], 273 | offset: [ 274 | 0, 275 | -60, // +0100 276 | 0 277 | ], 278 | until: [ 279 | 180000000, // 1970-01-03T02:00:00 280 | 262800000, // 1970-01-04T02:00:00 281 | null 282 | ] 283 | }); 284 | 285 | var second = new Second('1970-01-03T03:00:00', TEST_TIMEZONE); 286 | var prevSecond = second.toPrev(); 287 | 288 | ok(prevSecond !== second); 289 | 290 | ok(prevSecond.toStart().isEqual(new DateTime('1970-01-03T01:59:59+0000', TEST_TIMEZONE))); 291 | ok(prevSecond.toEnd().isEqual(new DateTime('1970-01-03T03:00:00+0100', TEST_TIMEZONE))); 292 | ok(prevSecond.valueOf() === 1000); 293 | }); 294 | 295 | /** 296 | * ---------------------------------------------------------------------------------------- 297 | * Display 298 | * ---------------------------------------------------------------------------------------- 299 | */ 300 | 301 | test('[Second] Display :: format', function () { 302 | var second = new Second('1970-01-03T03:00:00', UTC_TIMEZONE); 303 | ok(second.format('YYYY-MM-DD') === '1970-01-03 – 1970-01-03'); 304 | }); 305 | 306 | test('[Second] Display :: toISOString', function () { 307 | var second = new Second('1970-01-03T03:00:00', UTC_TIMEZONE); 308 | ok(second.toISOString() === '1970-01-03T03:00:00.000Z – 1970-01-03T03:00:01.000Z'); 309 | }); 310 | 311 | test('[Second] Display :: toLocaleString', function () { 312 | var second = new Second('1970-01-03T03:25:00', UTC_TIMEZONE); 313 | ok(second.toLocaleString() === '1/3/1970, 3:25:00 AM – 1/3/1970, 3:25:01 AM'); 314 | }); 315 | 316 | test('[Second] Display :: toString', function () { 317 | var second = new Second('1970-01-03T23:59:59', UTC_TIMEZONE); 318 | ok(second.toString() === 'Sat Jan 03 1970 23:59:59 GMT+0000 (UTC) – Sun Jan 04 1970 00:00:00 GMT+0000 (UTC)'); 319 | }); 320 | 321 | test('[Second] Display :: toUTCString', function () { 322 | var second = new Second('1970-01-03T14:59:45', UTC_TIMEZONE); 323 | ok(second.toUTCString() === 'Sat, 03 Jan 1970 14:59:45 GMT – Sat, 03 Jan 1970 14:59:46 GMT'); 324 | }); 325 | 326 | /** 327 | * ---------------------------------------------------------------------------------------- 328 | * Other methods 329 | * ---------------------------------------------------------------------------------------- 330 | */ 331 | 332 | test('[Second] toJSON', function () { 333 | var second = new Second('2016-05-01T14:30:59', UTC_TIMEZONE); 334 | ok(second.toJSON() === 'Sun May 01 2016 14:30:59 GMT+0000 (UTC) – Sun May 01 2016 14:31:00 GMT+0000 (UTC)'); 335 | }); 336 | 337 | test('[Second] valueOf', function () { 338 | var second; 339 | 340 | setTestTimezone({ 341 | abbr: [ 342 | 'TST', 343 | 'TST_1', 344 | 'TST' 345 | ], 346 | dst: [ 347 | false, 348 | true, 349 | false 350 | ], 351 | offset: [ 352 | 0, 353 | -60, // +0100 354 | 0 355 | ], 356 | until: [ 357 | 180000000, // 1970-01-03T02:00:00 358 | 262800000, // 1970-01-04T02:00:00 359 | null 360 | ] 361 | }); 362 | 363 | second = new Second('2016-08-01T12:59:59.444', UTC_TIMEZONE); 364 | ok(second.valueOf() === 1000); 365 | 366 | second = new Second('1970-01-03T02:59:59+0100', TEST_TIMEZONE); 367 | ok(second.valueOf() === 1000); 368 | }); 369 | })(); 370 | -------------------------------------------------------------------------------- /test/unit/spec/calendar/week.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var UTC_TIMEZONE = 'UTC'; 11 | 12 | var test = createTestFn(); 13 | 14 | var Month = DateTime.Month; 15 | var MonthWeeks = DateTime.MonthWeeks; 16 | var Week = DateTime.Week; 17 | var Year = DateTime.Year; 18 | var Interval = DateTime.Interval; 19 | 20 | /** 21 | * ---------------------------------------------------------------------------------------- 22 | * Class 23 | * ---------------------------------------------------------------------------------------- 24 | */ 25 | 26 | test('[Week] Class', function () { 27 | ok(typeof Week === 'function'); 28 | }); 29 | 30 | /** 31 | * ---------------------------------------------------------------------------------------- 32 | * Create 33 | * ---------------------------------------------------------------------------------------- 34 | */ 35 | 36 | test('[Week] Create :: No arguments', function () { 37 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 38 | 39 | mockNow(864000000); 40 | 41 | var week = new Week(); 42 | 43 | ok(week instanceof Week); 44 | ok(week instanceof Interval); 45 | 46 | ok(week.toStart().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0]))); 47 | ok(week.toEnd().isEqual(new DateTime([1970, 1, 18, 0, 0, 0, 0]))); 48 | }); 49 | 50 | test('[Week] Create :: DateTime', function () { 51 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 52 | 53 | var dt = new DateTime([1970, 1, 11, 14, 0, 0, 0], UTC_TIMEZONE); 54 | var week = new Week(dt); 55 | 56 | ok(week.toStart() !== dt); 57 | ok(week.toStart().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0])) === true); 58 | ok(week.toEnd().isEqual(new DateTime([1970, 1, 18, 0, 0, 0, 0])) === true); 59 | 60 | // Original date shouldn't be altered 61 | ok(dt.isEqual(new DateTime([1970, 1, 11, 14, 0, 0, 0])) === true); 62 | }); 63 | 64 | test('[Week] Create :: String', function () { 65 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 66 | 67 | var week = new Week('1970-01-11'); 68 | 69 | ok(week.toStart().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0]))); 70 | ok(week.toEnd().isEqual(new DateTime([1970, 1, 18, 0, 0, 0, 0]))); 71 | }); 72 | 73 | test('[Week] Create :: Number', function () { 74 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 75 | 76 | var week = new Week(914400000); 77 | 78 | ok(week.toStart().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0]))); 79 | ok(week.toEnd().isEqual(new DateTime([1970, 1, 18, 0, 0, 0, 0]))); 80 | }); 81 | 82 | test('[Week] Create :: String and timezone', function () { 83 | setTestTimezone({ 84 | abbr: [ 85 | 'TST', 86 | 'TST_1', 87 | 'TST' 88 | ], 89 | dst: [ 90 | false, 91 | true, 92 | false 93 | ], 94 | offset: [ 95 | 0, 96 | -60, // +0100 97 | 0 98 | ], 99 | until: [ 100 | 180000000, // 1970-01-03T02:00:00 101 | 262800000, // 1970-01-04T02:00:00 102 | null 103 | ] 104 | }); 105 | 106 | var week = new Week('1970-01-03T03:00:00+0100', TEST_TIMEZONE); 107 | 108 | ok(week.toStart().isEqual(new DateTime([1969, 12, 28, 0, 0, 0, 0], TEST_TIMEZONE))); 109 | ok(week.toEnd().isEqual(new DateTime([1970, 1, 4, 0, 0, 0, 0], TEST_TIMEZONE))); 110 | }); 111 | 112 | /** 113 | * ---------------------------------------------------------------------------------------- 114 | * Getters 115 | * ---------------------------------------------------------------------------------------- 116 | */ 117 | 118 | test('[Week] getWeekOfYear', function () { 119 | var week = new Week('1979-05-03', UTC_TIMEZONE); 120 | ok(week.getWeekOfYear() === 18); 121 | }); 122 | 123 | /** 124 | * ---------------------------------------------------------------------------------------- 125 | * Next week 126 | * ---------------------------------------------------------------------------------------- 127 | */ 128 | 129 | test('[Week] toNext', function () { 130 | var week = new Week('1970-01-11T03:00:00', UTC_TIMEZONE); 131 | var nextWeek = week.toNext(); 132 | 133 | ok(nextWeek !== week); 134 | 135 | ok(nextWeek.toStart().isEqual(new DateTime([1970, 1, 18, 0, 0, 0, 0]))); 136 | ok(nextWeek.toEnd().isEqual(new DateTime([1970, 1, 25, 0, 0, 0, 0]))); 137 | 138 | // Original week isn't altered 139 | ok(week.toStart().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0]))); 140 | ok(week.toEnd().isEqual(new DateTime([1970, 1, 18, 0, 0, 0, 0]))); 141 | }); 142 | 143 | test('[Week] toNext :: Next month', function () { 144 | var week = new Week('1970-11-25T05:00:00', UTC_TIMEZONE); 145 | var nextWeek = week.toNext(); 146 | 147 | ok(nextWeek.toStart().isEqual(new DateTime([1970, 11, 29, 0, 0, 0, 0]))); 148 | ok(nextWeek.toEnd().isEqual(new DateTime([1970, 12, 6, 0, 0, 0, 0]))); 149 | }); 150 | 151 | test('[Week] toNext :: Next year', function () { 152 | var week = new Week('1970-12-26T14:00:00', UTC_TIMEZONE); 153 | var nextWeek = week.toNext(); 154 | 155 | ok(nextWeek.toStart().isEqual(new DateTime([1970, 12, 27, 0, 0, 0, 0]))); 156 | ok(nextWeek.toEnd().isEqual(new DateTime([1971, 1, 3, 0, 0, 0, 0]))); 157 | }); 158 | 159 | test('[Week] toNext :: Timezone', function () { 160 | setTestTimezone({ 161 | abbr: [ 162 | 'TST', 163 | 'TST_1', 164 | 'TST' 165 | ], 166 | dst: [ 167 | false, 168 | true, 169 | false 170 | ], 171 | offset: [ 172 | 0, 173 | -60, // +0100 174 | 0 175 | ], 176 | until: [ 177 | 180000000, // 1970-01-03T02:00:00 178 | 262800000, // 1970-01-04T02:00:00 179 | null 180 | ] 181 | }); 182 | 183 | var week = new Week('1970-01-02T14:00:00', TEST_TIMEZONE); 184 | var nextWeek = week.toNext(); 185 | 186 | ok(nextWeek !== week); 187 | 188 | ok(nextWeek.toStart().isEqual(new DateTime([1970, 1, 4, 0, 0, 0, 0], TEST_TIMEZONE))); 189 | ok(nextWeek.toEnd().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0], TEST_TIMEZONE))); 190 | }); 191 | 192 | /** 193 | * ---------------------------------------------------------------------------------------- 194 | * Previous week 195 | * ---------------------------------------------------------------------------------------- 196 | */ 197 | 198 | test('[Week] toPrev', function () { 199 | var week = new Week('1970-01-15T03:00:00+0100', UTC_TIMEZONE); 200 | var prevWeek = week.toPrev(); 201 | 202 | ok(prevWeek !== week); 203 | 204 | ok(prevWeek.toStart().isEqual(new DateTime([1970, 1, 4, 0, 0, 0, 0]))); 205 | ok(prevWeek.toEnd().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0]))); 206 | 207 | // Original week isn't altered 208 | ok(week.toStart().isEqual(new DateTime([1970, 1, 11, 0, 0, 0, 0]))); 209 | ok(week.toEnd().isEqual(new DateTime([1970, 1, 18, 0, 0, 0, 0]))); 210 | }); 211 | 212 | test('[Week] toPrev :: Previous month', function () { 213 | var week = new Week('1970-05-05T00:30:00', UTC_TIMEZONE); 214 | var prevWeek = week.toPrev(); 215 | 216 | ok(prevWeek.toStart().isEqual(new DateTime([1970, 4, 26, 0, 0, 0, 0]))); 217 | ok(prevWeek.toEnd().isEqual(new DateTime([1970, 5, 3, 0, 0, 0, 0]))); 218 | }); 219 | 220 | test('[Week] toPrev :: Previous year', function () { 221 | var week = new Week('1970-01-05T00:30:00', UTC_TIMEZONE); 222 | var prevWeek = week.toPrev(); 223 | 224 | ok(prevWeek.toStart().isEqual(new DateTime([1969, 12, 28, 0, 0, 0, 0]))); 225 | ok(prevWeek.toEnd().isEqual(new DateTime([1970, 1, 4, 0, 0, 0, 0]))); 226 | }); 227 | 228 | test('[Week] toPrev :: Timezone', function () { 229 | setTestTimezone({ 230 | abbr: [ 231 | 'TST', 232 | 'TST_1', 233 | 'TST' 234 | ], 235 | dst: [ 236 | false, 237 | true, 238 | false 239 | ], 240 | offset: [ 241 | 0, 242 | -60, // +0100 243 | 0 244 | ], 245 | until: [ 246 | 180000000, // 1970-01-03T02:00:00 247 | 262800000, // 1970-01-04T02:00:00 248 | null 249 | ] 250 | }); 251 | 252 | var week = new Week('1970-01-03T03:00:00+0100', TEST_TIMEZONE); 253 | var prevWeek = week.toPrev(); 254 | 255 | ok(prevWeek !== week); 256 | 257 | ok(prevWeek.toStart().isEqual(new DateTime([1969, 12, 21, 0, 0, 0, 0], TEST_TIMEZONE))); 258 | ok(prevWeek.toEnd().isEqual(new DateTime([1969, 12, 28, 0, 0, 0, 0], TEST_TIMEZONE))); 259 | }); 260 | 261 | /** 262 | * ---------------------------------------------------------------------------------------- 263 | * toDays 264 | * ---------------------------------------------------------------------------------------- 265 | */ 266 | 267 | test('[Week] toDays', function () { 268 | var week = new Week('2017-05-15', UTC_TIMEZONE); 269 | var days = week.toDays(); 270 | 271 | ok(days.length === 7); 272 | 273 | ok(days[0].toStart().isEqual(new DateTime([2017, 5, 14, 0, 0, 0, 0], UTC_TIMEZONE))); 274 | ok(days[0].toEnd().isEqual(new DateTime([2017, 5, 15, 0, 0, 0, 0], UTC_TIMEZONE))); 275 | 276 | ok(days[1].toStart().isEqual(new DateTime([2017, 5, 15, 0, 0, 0, 0], UTC_TIMEZONE))); 277 | ok(days[1].toEnd().isEqual(new DateTime([2017, 5, 16, 0, 0, 0, 0], UTC_TIMEZONE))); 278 | 279 | ok(days[2].toStart().isEqual(new DateTime([2017, 5, 16, 0, 0, 0, 0], UTC_TIMEZONE))); 280 | ok(days[2].toEnd().isEqual(new DateTime([2017, 5, 17, 0, 0, 0, 0], UTC_TIMEZONE))); 281 | 282 | ok(days[3].toStart().isEqual(new DateTime([2017, 5, 17, 0, 0, 0, 0], UTC_TIMEZONE))); 283 | ok(days[3].toEnd().isEqual(new DateTime([2017, 5, 18, 0, 0, 0, 0], UTC_TIMEZONE))); 284 | 285 | ok(days[4].toStart().isEqual(new DateTime([2017, 5, 18, 0, 0, 0, 0], UTC_TIMEZONE))); 286 | ok(days[4].toEnd().isEqual(new DateTime([2017, 5, 19, 0, 0, 0, 0], UTC_TIMEZONE))); 287 | 288 | ok(days[5].toStart().isEqual(new DateTime([2017, 5, 19, 0, 0, 0, 0], UTC_TIMEZONE))); 289 | ok(days[5].toEnd().isEqual(new DateTime([2017, 5, 20, 0, 0, 0, 0], UTC_TIMEZONE))); 290 | 291 | ok(days[6].toStart().isEqual(new DateTime([2017, 5, 20, 0, 0, 0, 0], UTC_TIMEZONE))); 292 | ok(days[6].toEnd().isEqual(new DateTime([2017, 5, 21, 0, 0, 0, 0], UTC_TIMEZONE))); 293 | }); 294 | 295 | test('[Week] toDays :: Timezone', function () { 296 | setTestTimezone({ 297 | abbr: [ 298 | 'TST', 299 | 'TST_1' 300 | ], 301 | dst: [ 302 | false, 303 | true 304 | ], 305 | offset: [ 306 | 0, 307 | -60 // +0100 308 | ], 309 | until: [ 310 | 180000000, // 1970-01-03T02:00:00 311 | null 312 | ] 313 | }); 314 | 315 | var week = new Week('2017-05-15', TEST_TIMEZONE); 316 | var days = week.toDays(); 317 | 318 | ok(days.length === 7); 319 | 320 | ok(days[0].toStart().isEqual(new DateTime([2017, 5, 14, 0, 0, 0, 0], TEST_TIMEZONE))); 321 | ok(days[0].toEnd().isEqual(new DateTime([2017, 5, 15, 0, 0, 0, 0], TEST_TIMEZONE))); 322 | 323 | ok(days[1].toStart().isEqual(new DateTime([2017, 5, 15, 0, 0, 0, 0], TEST_TIMEZONE))); 324 | ok(days[1].toEnd().isEqual(new DateTime([2017, 5, 16, 0, 0, 0, 0], TEST_TIMEZONE))); 325 | 326 | ok(days[2].toStart().isEqual(new DateTime([2017, 5, 16, 0, 0, 0, 0], TEST_TIMEZONE))); 327 | ok(days[2].toEnd().isEqual(new DateTime([2017, 5, 17, 0, 0, 0, 0], TEST_TIMEZONE))); 328 | 329 | ok(days[3].toStart().isEqual(new DateTime([2017, 5, 17, 0, 0, 0, 0], TEST_TIMEZONE))); 330 | ok(days[3].toEnd().isEqual(new DateTime([2017, 5, 18, 0, 0, 0, 0], TEST_TIMEZONE))); 331 | 332 | ok(days[4].toStart().isEqual(new DateTime([2017, 5, 18, 0, 0, 0, 0], TEST_TIMEZONE))); 333 | ok(days[4].toEnd().isEqual(new DateTime([2017, 5, 19, 0, 0, 0, 0], TEST_TIMEZONE))); 334 | 335 | ok(days[5].toStart().isEqual(new DateTime([2017, 5, 19, 0, 0, 0, 0], TEST_TIMEZONE))); 336 | ok(days[5].toEnd().isEqual(new DateTime([2017, 5, 20, 0, 0, 0, 0], TEST_TIMEZONE))); 337 | 338 | ok(days[6].toStart().isEqual(new DateTime([2017, 5, 20, 0, 0, 0, 0], TEST_TIMEZONE))); 339 | ok(days[6].toEnd().isEqual(new DateTime([2017, 5, 21, 0, 0, 0, 0], TEST_TIMEZONE))); 340 | }); 341 | 342 | /** 343 | * ---------------------------------------------------------------------------------------- 344 | * Display 345 | * ---------------------------------------------------------------------------------------- 346 | */ 347 | 348 | test('[Week] Display :: format', function () { 349 | var week = new Week('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 350 | ok(week.format('YYYY-MM-DD') === '1969-12-28 – 1970-01-04'); 351 | }); 352 | 353 | test('[Week] Display :: toISOString', function () { 354 | var week = new Week('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 355 | ok(week.toISOString() === '1969-12-28T00:00:00.000Z – 1970-01-04T00:00:00.000Z'); 356 | }); 357 | 358 | test('[Week] Display :: toLocaleString', function () { 359 | var week = new Week('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 360 | ok(week.toLocaleString() === '12/28/1969, 12:00:00 AM – 1/4/1970, 12:00:00 AM'); 361 | }); 362 | 363 | test('[Week] Display :: toString', function () { 364 | var week = new Week('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 365 | ok(week.toString() === 'Sun Dec 28 1969 00:00:00 GMT+0000 (UTC) – Sun Jan 04 1970 00:00:00 GMT+0000 (UTC)'); 366 | }); 367 | 368 | test('[Week] Display :: toUTCString', function () { 369 | var week = new Week('1970-01-03T03:00:00+0100', UTC_TIMEZONE); 370 | ok(week.toUTCString() === 'Sun, 28 Dec 1969 00:00:00 GMT – Sun, 04 Jan 1970 00:00:00 GMT'); 371 | }); 372 | 373 | /** 374 | * ---------------------------------------------------------------------------------------- 375 | * Other methods 376 | * ---------------------------------------------------------------------------------------- 377 | */ 378 | 379 | test('[Month] toJSON', function () { 380 | var week = new Week('2016-05-01T14:30:00', UTC_TIMEZONE); 381 | ok(week.toJSON() === 'Sun May 01 2016 00:00:00 GMT+0000 (UTC) – Sun May 08 2016 00:00:00 GMT+0000 (UTC)'); 382 | }); 383 | 384 | test('[Month] valueOf', function () { 385 | setTestTimezone({ 386 | abbr: [ 387 | 'TST', 388 | 'TST_1', 389 | 'TST' 390 | ], 391 | dst: [ 392 | false, 393 | true, 394 | false 395 | ], 396 | offset: [ 397 | 0, 398 | -60, // +0100 399 | 0 400 | ], 401 | until: [ 402 | 180000000, // 1970-01-03T02:00:00 403 | 262800000, // 1970-01-04T02:00:00 404 | null 405 | ] 406 | }); 407 | 408 | var week; 409 | 410 | week = new Week('2016-08-01T12:00:55.444', UTC_TIMEZONE); 411 | ok(week.valueOf() === 604800000); 412 | 413 | week = new Week('1970-01-03T03:00:00+0100', TEST_TIMEZONE); 414 | ok(week.valueOf() === 601200000); 415 | }); 416 | })(); 417 | -------------------------------------------------------------------------------- /test/unit/spec/clone.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var test = createTestFn(); 11 | 12 | var dt; 13 | var dt2; 14 | 15 | var MOSCOW_TIMEZONE = 'Europe/Moscow'; 16 | 17 | /** 18 | * ---------------------------------------------------------------------------------------- 19 | * Clone 20 | * ---------------------------------------------------------------------------------------- 21 | */ 22 | 23 | test('[Clone] UTC', function () { 24 | dt = new DateTime('2015-10-05T14:23:52+0300'); 25 | dt2 = dt.clone(); 26 | 27 | ok(dt !== dt2); 28 | ok(equalDates(dt, dt2) === true); 29 | }); 30 | 31 | test('[Clone] Timezone', function () { 32 | dt = new DateTime('2015-10-05T14:23:52+0300', MOSCOW_TIMEZONE); 33 | dt2 = dt.clone(); 34 | 35 | ok(dt !== dt2); 36 | ok(equalDates(dt, dt2) === true); 37 | }); 38 | })(); 39 | -------------------------------------------------------------------------------- /test/unit/spec/duration/duration.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var UTC_TIMEZONE = 'UTC'; 11 | 12 | var test = createTestFn(); 13 | var Duration = DateTime.Duration; 14 | 15 | function getAttributes (duration) { 16 | return [ 17 | duration.getYears(), 18 | duration.getMonths(), 19 | duration.getDays(), 20 | duration.getHours(), 21 | duration.getMinutes(), 22 | duration.getSeconds() 23 | ]; 24 | } 25 | 26 | function isInvalid (duration) { 27 | return duration.isValid() === false && 28 | duration.isInvalid() === true && 29 | duration.toString() === 'Invalid duration'; 30 | } 31 | 32 | /** 33 | * ---------------------------------------------------------------------------------------- 34 | * Class 35 | * ---------------------------------------------------------------------------------------- 36 | */ 37 | 38 | test('[Duration] Class', function () { 39 | ok(typeof Duration === 'function'); 40 | }); 41 | 42 | /** 43 | * ---------------------------------------------------------------------------------------- 44 | * Create instance 45 | * ---------------------------------------------------------------------------------------- 46 | */ 47 | 48 | test('[Duration] Create :: No arguments', function () { 49 | var duration = new Duration(); 50 | ok(equalArrays(getAttributes(duration), [0, 0, 0, 0, 0, 0])); 51 | }); 52 | 53 | test('[Duration] Create :: Positive', function () { 54 | var duration; 55 | 56 | duration = new Duration('P10Y'); 57 | ok(equalArrays(getAttributes(duration), [10, 0, 0, 0, 0, 0])); 58 | 59 | duration = new Duration('P10Y5M'); 60 | ok(equalArrays(getAttributes(duration), [10, 5, 0, 0, 0, 0])); 61 | 62 | duration = new Duration('P10Y5M12D'); 63 | ok(equalArrays(getAttributes(duration), [10, 5, 12, 0, 0, 0])); 64 | 65 | duration = new Duration('P10Y5M12DT14H'); 66 | ok(equalArrays(getAttributes(duration), [10, 5, 12, 14, 0, 0])); 67 | 68 | duration = new Duration('P10Y5M12DT14H55M'); 69 | ok(equalArrays(getAttributes(duration), [10, 5, 12, 14, 55, 0])); 70 | 71 | duration = new Duration('P10Y5M12DT14H55M01S'); 72 | ok(equalArrays(getAttributes(duration), [10, 5, 12, 14, 55, 1])); 73 | 74 | duration = new Duration('P10Y12D'); 75 | ok(equalArrays(getAttributes(duration), [10, 0, 12, 0, 0, 0])); 76 | 77 | duration = new Duration('P10Y5MT6M'); 78 | ok(equalArrays(getAttributes(duration), [10, 5, 0, 0, 6, 0])); 79 | 80 | duration = new Duration('P0010Y05MT06M'); 81 | ok(equalArrays(getAttributes(duration), [10, 5, 0, 0, 6, 0])); 82 | 83 | duration = new Duration('P10YT5M'); 84 | ok(equalArrays(getAttributes(duration), [10, 0, 0, 0, 5, 0])); 85 | }); 86 | 87 | test('[Duration] Create :: Negative', function () { 88 | var duration; 89 | 90 | duration = new Duration('-P10Y'); 91 | ok(equalArrays(getAttributes(duration), [-10, 0, 0, 0, 0, 0])); 92 | 93 | duration = new Duration('-P10Y5M'); 94 | ok(equalArrays(getAttributes(duration), [-10, -5, 0, 0, 0, 0])); 95 | 96 | duration = new Duration('-P10Y5M12D'); 97 | ok(equalArrays(getAttributes(duration), [-10, -5, -12, 0, 0, 0])); 98 | 99 | duration = new Duration('-P10Y5M12DT14H'); 100 | ok(equalArrays(getAttributes(duration), [-10, -5, -12, -14, 0, 0])); 101 | 102 | duration = new Duration('-P10Y5M12DT14H55M'); 103 | ok(equalArrays(getAttributes(duration), [-10, -5, -12, -14, -55, 0])); 104 | 105 | duration = new Duration('-P10Y5M12DT14H55M01S'); 106 | ok(equalArrays(getAttributes(duration), [-10, -5, -12, -14, -55, -1])); 107 | 108 | duration = new Duration('-P10Y12D'); 109 | ok(equalArrays(getAttributes(duration), [-10, 0, -12, 0, 0, 0])); 110 | 111 | duration = new Duration('-P10Y5MT6M'); 112 | ok(equalArrays(getAttributes(duration), [-10, -5, 0, 0, -6, 0])); 113 | 114 | duration = new Duration('-P0010Y05MT06M'); 115 | ok(equalArrays(getAttributes(duration), [-10, -5, 0, 0, -6, 0])); 116 | 117 | duration = new Duration('-P10YT5M'); 118 | ok(equalArrays(getAttributes(duration), [-10, 0, 0, 0, -5, 0])); 119 | }); 120 | 121 | /** 122 | * ---------------------------------------------------------------------------------------- 123 | * Getters 124 | * ---------------------------------------------------------------------------------------- 125 | */ 126 | 127 | test('[Duration] Getters', function () { 128 | var duration; 129 | 130 | duration = new Duration('P10Y5M12DT14H55M01S'); 131 | 132 | ok(duration.getYears() === 10); 133 | ok(duration.getMonths() === 5); 134 | ok(duration.getDays() === 12); 135 | ok(duration.getHours() === 14); 136 | ok(duration.getMinutes() === 55); 137 | ok(duration.getSeconds() === 1); 138 | 139 | duration = new Duration('P10Y12D'); 140 | 141 | ok(duration.getYears() === 10); 142 | ok(duration.getMonths() === 0); 143 | ok(duration.getDays() === 12); 144 | ok(duration.getHours() === 0); 145 | ok(duration.getMinutes() === 0); 146 | ok(duration.getSeconds() === 0); 147 | }); 148 | 149 | /** 150 | * ---------------------------------------------------------------------------------------- 151 | * Display 152 | * ---------------------------------------------------------------------------------------- 153 | */ 154 | 155 | test('[Duration] toString :: Positive', function () { 156 | var duration; 157 | 158 | duration = new Duration('P10Y5M12DT14H55M01S'); 159 | ok(duration.toString() === 'P10Y5M12DT14H55M1S'); 160 | 161 | duration = new Duration('P10Y12D'); 162 | ok(duration.toString() === 'P10Y12D'); 163 | 164 | duration = new Duration('P10Y12DT14H'); 165 | ok(duration.toString() === 'P10Y12DT14H'); 166 | 167 | duration = new Duration('P10YT12M'); 168 | ok(duration.toString() === 'P10YT12M'); 169 | }); 170 | 171 | test('[Duration] toString :: Negative', function () { 172 | var duration; 173 | 174 | duration = new Duration('-P10Y5M12DT14H55M01S'); 175 | ok(duration.toString() === '-P10Y5M12DT14H55M1S'); 176 | 177 | duration = new Duration('-P10Y12D'); 178 | ok(duration.toString() === '-P10Y12D'); 179 | 180 | duration = new Duration('-P10Y12DT14H'); 181 | ok(duration.toString() === '-P10Y12DT14H'); 182 | 183 | duration = new Duration('-P10YT12M'); 184 | ok(duration.toString() === '-P10YT12M'); 185 | }); 186 | 187 | test('[Duration] toISOString :: Positive', function () { 188 | var duration; 189 | 190 | duration = new Duration('P10Y5M12DT14H55M01S'); 191 | ok(duration.toISOString() === 'P10Y5M12DT14H55M1S'); 192 | 193 | duration = new Duration('P10Y12D'); 194 | ok(duration.toISOString() === 'P10Y12D'); 195 | 196 | duration = new Duration('P10Y12DT14H'); 197 | ok(duration.toISOString() === 'P10Y12DT14H'); 198 | 199 | duration = new Duration('P10YT12M'); 200 | ok(duration.toISOString() === 'P10YT12M'); 201 | }); 202 | 203 | test('[Duration] toISOString :: Negative', function () { 204 | var duration; 205 | 206 | duration = new Duration('-P10Y5M12DT14H55M01S'); 207 | ok(duration.toISOString() === '-P10Y5M12DT14H55M1S'); 208 | 209 | duration = new Duration('-P10Y12D'); 210 | ok(duration.toISOString() === '-P10Y12D'); 211 | 212 | duration = new Duration('-P10Y12DT14H'); 213 | ok(duration.toISOString() === '-P10Y12DT14H'); 214 | 215 | duration = new Duration('-P10YT12M'); 216 | ok(duration.toISOString() === '-P10YT12M'); 217 | }); 218 | 219 | /** 220 | * ---------------------------------------------------------------------------------------- 221 | * Misc 222 | * ---------------------------------------------------------------------------------------- 223 | */ 224 | 225 | test('[Duration] isInvalid', function () { 226 | var duration; 227 | 228 | duration = new Duration('P10Y12D'); 229 | ok(duration.isInvalid() === false); 230 | 231 | duration = new Duration(); 232 | ok(duration.isInvalid() === false); 233 | 234 | duration = new Duration('bla'); 235 | ok(duration.isInvalid() === true); 236 | }); 237 | 238 | test('[Duration] isParsableAsDuration', function () { 239 | ok(Duration.isParsableAsDuration('P10Y12D') === true); 240 | ok(Duration.isParsableAsDuration('P10Y12DT') === true); 241 | ok(Duration.isParsableAsDuration('P10Y12DT14H') === true); 242 | ok(Duration.isParsableAsDuration('PT14H') === true); 243 | ok(Duration.isParsableAsDuration('P') === true); 244 | 245 | ok(Duration.isParsableAsDuration() === false); 246 | ok(Duration.isParsableAsDuration('') === false); 247 | 248 | ok(Duration.isParsableAsDuration('p') === false); 249 | ok(Duration.isParsableAsDuration('K') === false); 250 | 251 | ok(Duration.isParsableAsDuration('P10Ybla') === false); 252 | ok(Duration.isParsableAsDuration('P14H') === false); 253 | ok(Duration.isParsableAsDuration('P10M5Y') === false); 254 | }); 255 | })(); 256 | -------------------------------------------------------------------------------- /test/unit/spec/invalid.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var UTC_TIMEZONE = 'UTC'; 11 | 12 | var test = createTestFn(); 13 | var dt; 14 | var dt2; 15 | 16 | function createInvalidDate () { 17 | return new DateTime('bla'); 18 | } 19 | 20 | /** 21 | * ---------------------------------------------------------------------------------------- 22 | * Create 23 | * ---------------------------------------------------------------------------------------- 24 | */ 25 | 26 | test('[Invalid date] Create :: Non-parsable string', function () { 27 | dt = new DateTime('bla', UTC_TIMEZONE); 28 | ok(dt.isInvalid() === true); 29 | }); 30 | 31 | test('[Invalid date] Create :: NaN', function () { 32 | dt = new DateTime(NaN, UTC_TIMEZONE); 33 | ok(dt.isInvalid() === true); 34 | }); 35 | 36 | test('[Invalid date] Create :: Array with unsupported types', function () { 37 | dt = new DateTime([2016, '10', 5], UTC_TIMEZONE); 38 | ok(dt.isInvalid() === true); 39 | }); 40 | 41 | test('[Invalid date] Create :: Array with NaN', function () { 42 | dt = new DateTime([2016, 10, 5, NaN], UTC_TIMEZONE); 43 | ok(dt.isInvalid() === true); 44 | }); 45 | 46 | test('[Invalid date] Create :: Clone', function () { 47 | dt = new DateTime([2016, 10, 5, NaN], UTC_TIMEZONE); 48 | dt2 = dt.clone(); 49 | 50 | ok(dt2.isInvalid() === true, 'dt2.isInvalid() === true'); 51 | ok(dt2.isEqual(dt) === false, 'dt2.isEqual(dt) === false'); 52 | 53 | ok(dt2 !== dt, 'dt2 !== dt'); 54 | }); 55 | 56 | /** 57 | * ---------------------------------------------------------------------------------------- 58 | * Getters 59 | * ---------------------------------------------------------------------------------------- 60 | */ 61 | 62 | test('[Invalid date] Getters :: getYear', function () { 63 | dt = createInvalidDate(); 64 | ok(isNaN(dt.getYear()) === true); 65 | }); 66 | 67 | test('[Invalid date] Getters :: getWeekYear', function () { 68 | dt = createInvalidDate(); 69 | ok(isNaN(dt.getWeekYear()) === true); 70 | }); 71 | 72 | test('[Invalid date] Getters :: getISOWeekYear', function () { 73 | dt = createInvalidDate(); 74 | ok(isNaN(dt.getISOWeekYear()) === true); 75 | }); 76 | 77 | test('[Invalid date] Getters :: getMonth', function () { 78 | dt = createInvalidDate(); 79 | ok(isNaN(dt.getMonth()) === true); 80 | }); 81 | 82 | test('[Invalid date] Getters :: getWeekOfYear', function () { 83 | dt = createInvalidDate(); 84 | ok(isNaN(dt.getWeekOfYear()) === true); 85 | }); 86 | 87 | test('[Invalid date] Getters :: getISOWeekOfYear', function () { 88 | dt = createInvalidDate(); 89 | ok(isNaN(dt.getISOWeekOfYear()) === true); 90 | }); 91 | 92 | test('[Invalid date] Getters :: getDayOfMonth', function () { 93 | dt = createInvalidDate(); 94 | ok(isNaN(dt.getDayOfMonth()) === true); 95 | }); 96 | 97 | test('[Invalid date] Getters :: getDayOfWeek', function () { 98 | dt = createInvalidDate(); 99 | ok(isNaN(dt.getDayOfWeek()) === true); 100 | }); 101 | 102 | test('[Invalid date] Getters :: getHour', function () { 103 | dt = createInvalidDate(); 104 | ok(isNaN(dt.getHour()) === true); 105 | }); 106 | 107 | test('[Invalid date] Getters :: getMinute', function () { 108 | dt = createInvalidDate(); 109 | ok(isNaN(dt.getMinute()) === true); 110 | }); 111 | 112 | test('[Invalid date] Getters :: getSecond', function () { 113 | dt = createInvalidDate(); 114 | ok(isNaN(dt.getSecond()) === true); 115 | }); 116 | 117 | test('[Invalid date] Getters :: getMillisecond', function () { 118 | dt = createInvalidDate(); 119 | ok(isNaN(dt.getMillisecond()) === true); 120 | }); 121 | 122 | test('[Invalid date] Getters :: getUTCYear', function () { 123 | dt = createInvalidDate(); 124 | ok(isNaN(dt.getUTCYear()) === true); 125 | }); 126 | 127 | test('[Invalid date] Getters :: getUTCMonth', function () { 128 | dt = createInvalidDate(); 129 | ok(isNaN(dt.getUTCMonth()) === true); 130 | }); 131 | 132 | test('[Invalid date] Getters :: getUTCDayOfMonth', function () { 133 | dt = createInvalidDate(); 134 | ok(isNaN(dt.getUTCDayOfMonth()) === true); 135 | }); 136 | 137 | test('[Invalid date] Getters :: getUTCDayOfWeek', function () { 138 | dt = createInvalidDate(); 139 | ok(isNaN(dt.getUTCDayOfWeek()) === true); 140 | }); 141 | 142 | test('[Invalid date] Getters :: getUTCHour', function () { 143 | dt = createInvalidDate(); 144 | ok(isNaN(dt.getUTCHour()) === true); 145 | }); 146 | 147 | test('[Invalid date] Getters :: getUTCMinute', function () { 148 | dt = createInvalidDate(); 149 | ok(isNaN(dt.getUTCMinute()) === true); 150 | }); 151 | 152 | test('[Invalid date] Getters :: getUTCSecond', function () { 153 | dt = createInvalidDate(); 154 | ok(isNaN(dt.getUTCSecond()) === true); 155 | }); 156 | 157 | test('[Invalid date] Getters :: getUTCMillisecond', function () { 158 | dt = createInvalidDate(); 159 | ok(isNaN(dt.getUTCMillisecond()) === true); 160 | }); 161 | 162 | test('[Invalid date] Getters :: getTime', function () { 163 | dt = createInvalidDate(); 164 | ok(isNaN(dt.getTime()) === true); 165 | }); 166 | 167 | test('[Invalid date] Getters :: valueOf', function () { 168 | dt = createInvalidDate(); 169 | ok(isNaN(dt.valueOf()) === true); 170 | }); 171 | 172 | /** 173 | * ---------------------------------------------------------------------------------------- 174 | * Format 175 | * ---------------------------------------------------------------------------------------- 176 | */ 177 | 178 | test('[Invalid date] Format', function () { 179 | dt = createInvalidDate(); 180 | ok(dt.format() === 'Invalid date'); 181 | }); 182 | 183 | test('[Invalid date] Format :: toString', function () { 184 | dt = createInvalidDate(); 185 | ok(dt.toString() === 'Invalid date'); 186 | }); 187 | 188 | test('[Invalid date] Format :: toLocaleString', function () { 189 | dt = createInvalidDate(); 190 | ok(dt.toLocaleString() === 'Invalid date'); 191 | }); 192 | 193 | test('[Invalid date] Format :: toISOString', function () { 194 | dt = createInvalidDate(); 195 | ok(dt.toISOString() === 'Invalid date'); 196 | }); 197 | 198 | test('[Invalid date] Format :: toUTCString', function () { 199 | dt = createInvalidDate(); 200 | ok(dt.toUTCString() === 'Invalid date'); 201 | }); 202 | })(); 203 | -------------------------------------------------------------------------------- /test/unit/spec/is.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var test = createTestFn(); 11 | 12 | var Day = DateTime.Day; 13 | var Duration = DateTime.Duration; 14 | var Hour = DateTime.Hour; 15 | var Interval = DateTime.Interval; 16 | var Minute = DateTime.Minute; 17 | var Month = DateTime.Month; 18 | var MonthWeeks = DateTime.MonthWeeks; 19 | var Second = DateTime.Second; 20 | var Week = DateTime.Week; 21 | var Year = DateTime.Year; 22 | 23 | var TEST_TIMEZONE = 'TEST_TIMEZONE'; 24 | var UTC_TIMEZONE = 'UTC'; 25 | 26 | /** 27 | * ---------------------------------------------------------------------------------------- 28 | * Is instance of 29 | * ---------------------------------------------------------------------------------------- 30 | */ 31 | 32 | test('[DateTime] isDateTime', function () { 33 | ok(DateTime.isDateTime(new DateTime()) === true); 34 | ok(DateTime.isDateTime((new DateTime()).clone()) === true); 35 | ok(DateTime.isDateTime(new DateTime(NaN)) === true); 36 | 37 | ok(DateTime.isDateTime(new Date()) === false); 38 | ok(DateTime.isDateTime() === false); 39 | }); 40 | 41 | test('[DateTime] isDay', function () { 42 | ok(DateTime.isDay(new Day()) === true); 43 | ok(DateTime.isDay(new Day(NaN)) === true); 44 | 45 | ok(DateTime.isDay(new DateTime()) === false); 46 | ok(DateTime.isDay('2015-05-15') === false); 47 | ok(DateTime.isDay() === false); 48 | }); 49 | 50 | test('[DateTime] isDuration', function () { 51 | ok(DateTime.isDuration(new Duration()) === true); 52 | ok(DateTime.isDuration(new Duration('P5Y2M15D')) === true); 53 | ok(DateTime.isDuration(new Duration('')) === true); 54 | 55 | ok(DateTime.isDuration(new DateTime()) === false); 56 | ok(DateTime.isDuration('P5Y2M15D') === false); 57 | ok(DateTime.isDuration() === false); 58 | }); 59 | 60 | test('[DateTime] isHour', function () { 61 | ok(DateTime.isHour(new Hour()) === true); 62 | ok(DateTime.isHour(new Hour('')) === true); 63 | 64 | ok(DateTime.isHour(new DateTime()) === false); 65 | ok(DateTime.isHour('2015-10-05') === false); 66 | ok(DateTime.isHour() === false); 67 | }); 68 | 69 | test('[DateTime] isInterval', function () { 70 | ok(DateTime.isInterval(new Interval()) === true); 71 | ok(DateTime.isInterval(new Interval('')) === true); 72 | ok(DateTime.isInterval(new Interval(new DateTime(), new DateTime())) === true); 73 | ok(DateTime.isInterval(new Day()) === true); 74 | 75 | ok(DateTime.isInterval(new DateTime()) === false); 76 | ok(DateTime.isInterval('2015-10-05') === false); 77 | ok(DateTime.isInterval() === false); 78 | }); 79 | 80 | test('[DateTime] isMinute', function () { 81 | ok(DateTime.isMinute(new Minute()) === true); 82 | ok(DateTime.isMinute(new Minute('2015-10-05T14:00')) === true); 83 | 84 | ok(DateTime.isMinute(new DateTime()) === false); 85 | ok(DateTime.isMinute('2015-10-05') === false); 86 | ok(DateTime.isMinute() === false); 87 | }); 88 | 89 | test('[DateTime] isMonth', function () { 90 | ok(DateTime.isMonth(new Month()) === true); 91 | ok(DateTime.isMonth(new Month('2015-10')) === true); 92 | 93 | ok(DateTime.isMonth(new DateTime()) === false); 94 | ok(DateTime.isMonth('2015-10-05') === false); 95 | ok(DateTime.isMonth() === false); 96 | }); 97 | 98 | test('[DateTime] isMonthWeeks', function () { 99 | ok(DateTime.isMonthWeeks(new MonthWeeks()) === true); 100 | ok(DateTime.isMonthWeeks(new MonthWeeks('2015-10')) === true); 101 | 102 | ok(DateTime.isMonthWeeks(new DateTime()) === false); 103 | ok(DateTime.isMonthWeeks('2015-10-05') === false); 104 | ok(DateTime.isMonthWeeks() === false); 105 | }); 106 | 107 | test('[DateTime] isSecond', function () { 108 | ok(DateTime.isSecond(new Second()) === true); 109 | ok(DateTime.isSecond(new Second('2015-10-05T14:00:00')) === true); 110 | 111 | ok(DateTime.isSecond(new DateTime()) === false); 112 | ok(DateTime.isSecond('2015-10-05') === false); 113 | ok(DateTime.isSecond() === false); 114 | }); 115 | 116 | test('[DateTime] isWeek', function () { 117 | ok(DateTime.isWeek(new Week()) === true); 118 | ok(DateTime.isWeek(new Week('2015-10-05')) === true); 119 | 120 | ok(DateTime.isWeek(new DateTime()) === false); 121 | ok(DateTime.isWeek('2015-10-05') === false); 122 | ok(DateTime.isWeek() === false); 123 | }); 124 | 125 | test('[DateTime] isYear', function () { 126 | ok(DateTime.isYear(new Year()) === true); 127 | ok(DateTime.isYear(new Year('2015')) === true); 128 | 129 | ok(DateTime.isYear(new DateTime()) === false); 130 | ok(DateTime.isYear('2015-10-05') === false); 131 | ok(DateTime.isYear() === false); 132 | }); 133 | 134 | /** 135 | * ---------------------------------------------------------------------------------------- 136 | * DST 137 | * ---------------------------------------------------------------------------------------- 138 | */ 139 | 140 | test('[DST] isDST', function () { 141 | var dt; 142 | 143 | setTestTimezone({ 144 | abbr: [ 145 | 'TEST_1', 146 | 'TEST_2', 147 | 'TEST_3', 148 | 'TEST_4', 149 | 'TEST_5' 150 | ], 151 | dst: [ 152 | false, 153 | true, 154 | false, 155 | true, 156 | false 157 | ], 158 | offset: [ 159 | -180, // +0300 160 | 180, // -0300 161 | -270, // +0400 162 | 15, // -0015 163 | -240 // -0400 164 | ], 165 | until: [ 166 | 10 * 365 * 24 * 60 * 60 * 1000, 167 | 20 * 365 * 24 * 60 * 60 * 1000, 168 | 30 * 365 * 24 * 60 * 60 * 1000, 169 | 40 * 365 * 24 * 60 * 60 * 1000, 170 | null 171 | ] 172 | }); 173 | 174 | dt = new DateTime([2014, 5, 31, 22, 15, 0, 41], 'UTC'); 175 | ok(dt.isDST() === false); 176 | 177 | dt = new DateTime([1960, 1, 1, 22, 15, 0, 41], TEST_TIMEZONE); 178 | ok(dt.isDST() === false); 179 | 180 | dt = new DateTime([1970, 1, 1, 22, 15, 0, 41], TEST_TIMEZONE); 181 | ok(dt.isDST() === false); 182 | 183 | dt = new DateTime(10 * 365 * 24 * 60 * 60 * 1000 - 1, TEST_TIMEZONE); 184 | ok(dt.isDST() === false); 185 | 186 | dt = new DateTime(10 * 365 * 24 * 60 * 60 * 1000, TEST_TIMEZONE); 187 | ok(dt.isDST() === true); 188 | 189 | dt = new DateTime([1985, 1, 1, 22, 15, 0, 41], TEST_TIMEZONE); 190 | ok(dt.isDST() === true); 191 | 192 | dt = new DateTime([1995, 1, 1, 22, 15, 0, 41], TEST_TIMEZONE); 193 | ok(dt.isDST() === false); 194 | 195 | dt = new DateTime([2005, 1, 1, 22, 15, 0, 41], TEST_TIMEZONE); 196 | ok(dt.isDST() === true); 197 | 198 | dt = new DateTime([2015, 1, 1, 22, 15, 0, 41], TEST_TIMEZONE); 199 | ok(dt.isDST() === false); 200 | 201 | dt = new DateTime([2025, 1, 1, 22, 15, 0, 41], TEST_TIMEZONE); 202 | ok(dt.isDST() === false); 203 | }); 204 | 205 | /** 206 | * ---------------------------------------------------------------------------------------- 207 | * Is today 208 | * ---------------------------------------------------------------------------------------- 209 | */ 210 | 211 | test('[DateTime] isToday :: UTC', function () { 212 | var dt = new DateTime('2016-05-01T14:30:00', UTC_TIMEZONE); 213 | 214 | mockNow(1462060799999); // 2016-04-30T23:59:59.999Z 215 | ok(dt.isToday() === false); 216 | 217 | mockNow(1462060800000); // 2016-05-01T00:00:00Z 218 | ok(dt.isToday() === true); 219 | 220 | mockNow(1462111200000); // 2016-05-01T14:00:00Z 221 | ok(dt.isToday() === true); 222 | 223 | mockNow(1462147199999); // 2016-05-01T23:59:59.999Z 224 | ok(dt.isToday() === true); 225 | 226 | mockNow(1462147200000); // 2016-05-02T00:00:00Z 227 | ok(dt.isToday() === false); 228 | }); 229 | 230 | test('[DateTime] isToday :: Timezone', function () { 231 | setTestTimezone({ 232 | abbr: [ 233 | 'TST' 234 | ], 235 | dst: [ 236 | false 237 | ], 238 | offset: [ 239 | -240 // +0400 240 | ], 241 | until: [ 242 | null 243 | ] 244 | }); 245 | 246 | DateTime.setDefaultTimezone(TEST_TIMEZONE); 247 | 248 | var dt = new DateTime('2016-05-01T14:30:00', TEST_TIMEZONE); 249 | 250 | mockNow(1462046399999); // 2016-04-30T23:59:59.999+0400 251 | ok(dt.isToday() === false); 252 | 253 | mockNow(1462046400000); // 2016-05-01T00:00:00Z+0400 254 | ok(dt.isToday() === true); 255 | 256 | mockNow(1462096800000); // 2016-05-01T14:00:00Z+0400 257 | ok(dt.isToday() === true); 258 | 259 | mockNow(1462132799999); // 2016-05-01T23:59:59.999Z+0400 260 | ok(dt.isToday() === true); 261 | 262 | mockNow(1462132800000); // 2016-05-02T00:00:00Z+0400 263 | ok(dt.isToday() === false); 264 | }); 265 | 266 | /** 267 | * ---------------------------------------------------------------------------------------- 268 | * Is weekend 269 | * ---------------------------------------------------------------------------------------- 270 | */ 271 | 272 | test('[DateTime] isWeekend', function () { 273 | var dt; 274 | 275 | dt = new DateTime('2016-05-06T14:30:00', UTC_TIMEZONE); 276 | ok(dt.isWeekend() === false); 277 | 278 | dt = new DateTime('2016-05-07T14:30:00', UTC_TIMEZONE); 279 | ok(dt.isWeekend() === true); 280 | 281 | dt = new DateTime('2016-05-08T14:30:00', UTC_TIMEZONE); 282 | ok(dt.isWeekend() === true); 283 | 284 | dt = new DateTime('2016-05-09T14:30:00', UTC_TIMEZONE); 285 | ok(dt.isWeekend() === false); 286 | }); 287 | })(); 288 | -------------------------------------------------------------------------------- /test/unit/spec/locale.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var test = createTestFn(); 11 | 12 | /** 13 | * ---------------------------------------------------------------------------------------- 14 | * Locale 15 | * ---------------------------------------------------------------------------------------- 16 | */ 17 | 18 | test('[Locale] getLocale', function () { 19 | ok(DateTime.getLocale() === 'en'); 20 | }); 21 | 22 | test('[Locale] setLocale', function () { 23 | DateTime.setLocale('ru'); 24 | ok(DateTime.getLocale() === 'ru'); 25 | }); 26 | 27 | test('[Locale] setLocale :: Not found', function () { 28 | var err = null; 29 | 30 | DateTime.setLocale('en'); 31 | 32 | try { 33 | DateTime.setLocale('unknown'); 34 | } catch (ex) { 35 | err = ex; 36 | } 37 | 38 | ok(err !== null); 39 | ok(DateTime.getLocale() === 'en'); 40 | }); 41 | })(); 42 | -------------------------------------------------------------------------------- /test/unit/spec/misc.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var test = createTestFn(); 11 | var dt; 12 | 13 | var TEST_TIMEZONE = 'TEST_TIMEZONE'; 14 | var MOSCOW_TIMEZONE = 'Europe/Moscow'; 15 | var UTC_TIMEZONE = 'UTC'; 16 | 17 | /** 18 | * ---------------------------------------------------------------------------------------- 19 | * toString 20 | * ---------------------------------------------------------------------------------------- 21 | */ 22 | 23 | test('[toString] isEqual', function () { 24 | ok((new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE)).isEqual( 25 | new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE) 26 | ) === true); 27 | 28 | ok((new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE)).isEqual( 29 | new DateTime([2017, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE) 30 | ) === false); 31 | 32 | ok((new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE)).isEqual( 33 | new DateTime([2016, 11, 5, 14, 30, 45, 555], UTC_TIMEZONE) 34 | ) === false); 35 | 36 | ok((new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE)).isEqual( 37 | new DateTime([2016, 10, 6, 14, 30, 45, 555], UTC_TIMEZONE) 38 | ) === false); 39 | 40 | ok((new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE)).isEqual( 41 | new DateTime([2016, 10, 5, 15, 30, 45, 555], UTC_TIMEZONE) 42 | ) === false); 43 | 44 | ok((new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE)).isEqual( 45 | new DateTime([2016, 10, 5, 14, 31, 45, 555], UTC_TIMEZONE) 46 | ) === false); 47 | 48 | ok((new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE)).isEqual( 49 | new DateTime([2016, 10, 5, 14, 30, 46, 555], UTC_TIMEZONE) 50 | ) === false); 51 | 52 | ok((new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE)).isEqual( 53 | new DateTime([2016, 10, 5, 14, 30, 45, 556], UTC_TIMEZONE) 54 | ) === false); 55 | 56 | ok((new DateTime([2016, 10, 5, 14, 30, 45, 555], UTC_TIMEZONE)).isEqual( 57 | new DateTime([2016, 10, 5, 14, 30, 45, 555], MOSCOW_TIMEZONE) 58 | ) === false); 59 | }); 60 | 61 | /** 62 | * ---------------------------------------------------------------------------------------- 63 | * toString 64 | * ---------------------------------------------------------------------------------------- 65 | */ 66 | 67 | test('[toString] Basic', function () { 68 | dt = new DateTime([2014, 4, 5, 15, 20, 35, 41], MOSCOW_TIMEZONE); 69 | ok(dt.toString() === 'Sat Apr 05 2014 15:20:35 GMT+0400 (MSK)'); 70 | 71 | dt = new DateTime([1970, 1, 1, 14, 30, 49, 0], 'UTC'); 72 | ok(dt.toString() === 'Thu Jan 01 1970 14:30:49 GMT+0000 (UTC)'); 73 | }); 74 | 75 | test('[toString] Offset greater than 10', function () { 76 | dt = new DateTime([2014, 5, 10, 15, 20, 35, 41], 'Pacific/Wallis'); 77 | ok(dt.toString() === 'Sat May 10 2014 15:20:35 GMT+1200 (+12)'); 78 | }); 79 | 80 | test('[toString] Negative offset greater than 10', function () { 81 | dt = new DateTime([2014, 5, 10, 15, 20, 35, 41], 'US/Hawaii'); 82 | ok(dt.toString() === 'Sat May 10 2014 15:20:35 GMT-1000 (HST)'); 83 | }); 84 | 85 | test('[toString] Fractional offset', function () { 86 | dt = new DateTime([1980, 5, 10, 15, 20, 35, 41], 'Singapore'); 87 | ok(dt.toString() === 'Sat May 10 1980 15:20:35 GMT+0730 (+0730)'); 88 | }); 89 | 90 | /** 91 | * ---------------------------------------------------------------------------------------- 92 | * toLocaleString 93 | * ---------------------------------------------------------------------------------------- 94 | */ 95 | 96 | test('[toLocaleString] Basic', function () { 97 | DateTime.setLocale('en'); 98 | dt = new DateTime([2014, 4, 5, 15, 20, 35, 41], MOSCOW_TIMEZONE); 99 | ok(dt.toLocaleString() === '4/5/2014, 3:20:35 PM'); 100 | }); 101 | 102 | test('[toLocaleString] Offset greater than 10', function () { 103 | DateTime.setLocale('en'); 104 | dt = new DateTime([2014, 5, 10, 15, 20, 35, 41], 'Pacific/Wallis'); 105 | ok(dt.toLocaleString() === '5/10/2014, 3:20:35 PM'); 106 | }); 107 | 108 | test('[toLocaleString] Negative offset greater than 10', function () { 109 | DateTime.setLocale('en'); 110 | dt = new DateTime([2014, 5, 10, 15, 20, 35, 41], 'US/Hawaii'); 111 | ok(dt.toLocaleString() === '5/10/2014, 3:20:35 PM'); 112 | }); 113 | 114 | test('[toLocaleString] Fractional offset', function () { 115 | DateTime.setLocale('en'); 116 | dt = new DateTime([1980, 5, 10, 11, 20, 35, 41], 'Singapore'); 117 | ok(dt.toLocaleString() === '5/10/1980, 11:20:35 AM'); 118 | }); 119 | 120 | /** 121 | * ---------------------------------------------------------------------------------------- 122 | * toISOString 123 | * ---------------------------------------------------------------------------------------- 124 | */ 125 | 126 | test('[toISOString] Basic', function () { 127 | dt = new DateTime([2014, 4, 5, 15, 20, 35, 41], MOSCOW_TIMEZONE); 128 | ok(dt.toISOString() === '2014-04-05T11:20:35.041Z'); 129 | }); 130 | 131 | test('[toISOString] Offset greater than 10', function () { 132 | dt = new DateTime([2014, 5, 10, 15, 20, 35, 41], 'Pacific/Wallis'); 133 | ok(dt.toISOString() === '2014-05-10T03:20:35.041Z'); 134 | }); 135 | 136 | test('[toISOString] Negative offset greater than 10', function () { 137 | dt = new DateTime([2014, 5, 10, 15, 20, 35, 41], 'US/Hawaii'); 138 | ok(dt.toISOString() === '2014-05-11T01:20:35.041Z'); 139 | }); 140 | 141 | test('[toISOString] Fractional offset', function () { 142 | dt = new DateTime([1980, 5, 10, 15, 20, 35, 41], 'Singapore'); 143 | ok(dt.toISOString() === '1980-05-10T07:50:35.041Z'); 144 | }); 145 | 146 | /** 147 | * ---------------------------------------------------------------------------------------- 148 | * toUTCString 149 | * ---------------------------------------------------------------------------------------- 150 | */ 151 | 152 | test('[toUTCString] Basic', function () { 153 | dt = new DateTime([2014, 4, 5, 15, 20, 35, 41], MOSCOW_TIMEZONE); 154 | ok(dt.toUTCString() === 'Sat, 05 Apr 2014 11:20:35 GMT'); 155 | }); 156 | 157 | test('[toUTCString] Offset greater than 10', function () { 158 | dt = new DateTime([2014, 5, 10, 15, 20, 35, 41], 'Pacific/Wallis'); 159 | ok(dt.toUTCString() === 'Sat, 10 May 2014 03:20:35 GMT'); 160 | }); 161 | 162 | test('[toUTCString] Negative offset greater than 10', function () { 163 | dt = new DateTime([2014, 5, 9, 15, 20, 35, 41], 'US/Hawaii'); 164 | ok(dt.toUTCString() === 'Fri, 10 May 2014 01:20:35 GMT'); 165 | }); 166 | 167 | test('[toUTCString] Fractional offset', function () { 168 | dt = new DateTime([1980, 10, 5, 15, 20, 35, 41], 'Singapore'); 169 | ok(dt.toUTCString() === 'Sun, 05 Oct 1980 07:50:35 GMT'); 170 | }); 171 | 172 | /** 173 | * ---------------------------------------------------------------------------------------- 174 | * valueOf 175 | * ---------------------------------------------------------------------------------------- 176 | */ 177 | 178 | test('[valueOf] Basic', function () { 179 | dt = new DateTime([2014, 5, 10, 15, 20, 35, 41], MOSCOW_TIMEZONE); 180 | ok(dt.valueOf() === 1399720835041); 181 | }); 182 | 183 | /** 184 | * ---------------------------------------------------------------------------------------- 185 | * toJSON 186 | * ---------------------------------------------------------------------------------------- 187 | */ 188 | 189 | test('[toJSON] basic', function () { 190 | dt = new DateTime([2014, 5, 10, 15, 20, 35, 41], MOSCOW_TIMEZONE); 191 | ok(dt.toJSON() === dt.toISOString()); 192 | }); 193 | })(); 194 | -------------------------------------------------------------------------------- /test/unit/spec/now.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var test = createTestFn(); 5 | 6 | test('[DateTime.now]', function () { 7 | DateTime.setNow(function nowMock () { 8 | return 123; 9 | }); 10 | 11 | ok(DateTime.now() === 123); 12 | }); 13 | })(); 14 | -------------------------------------------------------------------------------- /test/unit/spec/timezone-default.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var AMSTERDAM_TIMEZONE = 'Europe/Amsterdam'; 11 | var MOSCOW_TIMEZONE = 'Europe/Moscow'; 12 | 13 | var test = createTestFn(); 14 | 15 | /** 16 | * ---------------------------------------------------------------------------------------- 17 | * Default Timezone 18 | * ---------------------------------------------------------------------------------------- 19 | */ 20 | 21 | test('[Default Timezone] setDefaultTimezone/getDefaultTimezone', function () { 22 | DateTime.setDefaultTimezone(AMSTERDAM_TIMEZONE); 23 | ok(DateTime.getDefaultTimezone() === AMSTERDAM_TIMEZONE); 24 | 25 | DateTime.setDefaultTimezone(MOSCOW_TIMEZONE); 26 | ok(DateTime.getDefaultTimezone() === MOSCOW_TIMEZONE); 27 | }); 28 | })(); 29 | 30 | -------------------------------------------------------------------------------- /test/unit/spec/timezone-info.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var TEST_TIMEZONE = 'TEST_TIMEZONE'; 11 | var MOSCOW_TIMEZONE = 'Europe/Moscow'; 12 | 13 | var test = createTestFn(); 14 | var dt; 15 | 16 | /** 17 | * ---------------------------------------------------------------------------------------- 18 | * Timezone info 19 | * ---------------------------------------------------------------------------------------- 20 | */ 21 | 22 | test('[Timezone info] getTimezoneInfo', function () { 23 | dt = new DateTime('2015-10-05T14:23:52+0300', MOSCOW_TIMEZONE); 24 | var tzinfo = dt.getTimezoneInfo(); 25 | 26 | ok(tzinfo.abbr === 'MSK'); 27 | ok(tzinfo.dst === false); 28 | ok(tzinfo.name === MOSCOW_TIMEZONE); 29 | ok(tzinfo.offset === -10800000); 30 | }); 31 | 32 | test('[Timezone info] getTimezoneName', function () { 33 | dt = new DateTime('2015-10-05T14:23:52+0300', MOSCOW_TIMEZONE); 34 | ok(dt.getTimezoneName() === MOSCOW_TIMEZONE); 35 | }); 36 | 37 | test('[Timezone info] getTimezoneOffset', function () { 38 | dt = new DateTime('2015-10-05T14:23:52+0300', MOSCOW_TIMEZONE); 39 | ok(dt.getTimezoneOffset() === -10800000); 40 | }); 41 | })(); 42 | -------------------------------------------------------------------------------- /test/unit/spec/transform-to.spec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * ---------------------------------------------------------------------------------------- 6 | * Prepare 7 | * ---------------------------------------------------------------------------------------- 8 | */ 9 | 10 | var Second = DateTime.Second; 11 | var Minute = DateTime.Minute; 12 | var Hour = DateTime.Hour; 13 | var Day = DateTime.Day; 14 | var Week = DateTime.Week; 15 | var Month = DateTime.Month; 16 | var MonthWeeks = DateTime.MonthWeeks; 17 | var Year = DateTime.Year; 18 | 19 | var UTC_TIMEZONE = 'UTC'; 20 | var TEST_TIMEZONE = 'TEST_TIMEZONE'; 21 | 22 | var test = createTestFn(); 23 | 24 | /** 25 | * ---------------------------------------------------------------------------------------- 26 | * toStartOf* 27 | * ---------------------------------------------------------------------------------------- 28 | */ 29 | 30 | test('[TransformTo] toStartOfSecond', function () { 31 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 32 | var dt2 = dt.toStartOfSecond(); 33 | 34 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 35 | ok(equalDates(dt2, new DateTime([2016, 10, 5, 14, 54, 13, 0]))); 36 | }); 37 | 38 | test('[TransformTo] toStartOfMinute', function () { 39 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 40 | var dt2 = dt.toStartOfMinute(); 41 | 42 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 43 | ok(equalDates(dt2, new DateTime([2016, 10, 5, 14, 54, 0, 0]))); 44 | }); 45 | 46 | test('[TransformTo] toStartOfHour', function () { 47 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 48 | var dt2 = dt.toStartOfHour(); 49 | 50 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 51 | ok(equalDates(dt2, new DateTime([2016, 10, 5, 14, 0, 0, 0]))); 52 | }); 53 | 54 | test('[TransformTo] toStartOfHour :: Ambiguous date', function () { 55 | setTestTimezone({ 56 | abbr: [ 57 | 'TST', 58 | 'TST_1', 59 | 'TST' 60 | ], 61 | dst: [ 62 | false, 63 | true, 64 | false 65 | ], 66 | offset: [ 67 | 0, 68 | -60, // +0100 69 | 0 70 | ], 71 | until: [ 72 | 180000000, // 1970-01-03T02:00:00 73 | 262800000, // 1970-01-04T02:00:00 74 | null 75 | ] 76 | }); 77 | 78 | var dt = new DateTime('1970-01-04T02:30:00+0000', TEST_TIMEZONE); 79 | var dt2 = dt.toStartOfHour(); 80 | 81 | ok(equalDates(dt, new DateTime('1970-01-04T02:30:00+0000', TEST_TIMEZONE))); 82 | ok(equalDates(dt2, new DateTime('1970-01-04T02:00:00+0000', TEST_TIMEZONE))); 83 | }); 84 | 85 | test('[TransformTo] toStartOfDay', function () { 86 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 87 | var dt2 = dt.toStartOfDay(); 88 | 89 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 90 | ok(equalDates(dt2, new DateTime([2016, 10, 5, 0, 0, 0, 0]))); 91 | }); 92 | 93 | test('[TransformTo] toStartOfWeek', function () { 94 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 95 | var dt2 = dt.toStartOfWeek(); 96 | 97 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 98 | ok(equalDates(dt2, new DateTime([2016, 10, 2, 0, 0, 0, 0]))); 99 | ok(dt2.getDayOfWeek() === 0); 100 | }); 101 | 102 | test('[TransformTo] toStartOfMonth', function () { 103 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 104 | var dt2 = dt.toStartOfMonth(); 105 | 106 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 107 | ok(equalDates(dt2, new DateTime([2016, 10, 1, 0, 0, 0, 0]))); 108 | }); 109 | 110 | test('[TransformTo] toStartOfYear', function () { 111 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 112 | var dt2 = dt.toStartOfYear(); 113 | 114 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 115 | ok(equalDates(dt2, new DateTime([2016, 1, 1, 0, 0, 0, 0]))); 116 | }); 117 | 118 | /** 119 | * ---------------------------------------------------------------------------------------- 120 | * toEndOf* 121 | * ---------------------------------------------------------------------------------------- 122 | */ 123 | 124 | test('[TransformTo] toEndOfSecond', function () { 125 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 126 | var dt2 = dt.toEndOfSecond(); 127 | 128 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 129 | ok(equalDates(dt2, new DateTime([2016, 10, 5, 14, 54, 13, 999]))); 130 | }); 131 | 132 | test('[TransformTo] toEndOfMinute', function () { 133 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 134 | var dt2 = dt.toEndOfMinute(); 135 | 136 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 137 | ok(equalDates(dt2, new DateTime([2016, 10, 5, 14, 54, 59, 999]))); 138 | }); 139 | 140 | test('[TransformTo] toEndOfHour', function () { 141 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 142 | var dt2 = dt.toEndOfHour(); 143 | 144 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 145 | ok(equalDates(dt2, new DateTime([2016, 10, 5, 14, 59, 59, 999]))); 146 | }); 147 | 148 | test('[TransformTo] toEndOfDay', function () { 149 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 150 | var dt2 = dt.toEndOfDay(); 151 | 152 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 153 | ok(equalDates(dt2, new DateTime([2016, 10, 5, 23, 59, 59, 999]))); 154 | }); 155 | 156 | test('[TransformTo] toEndOfWeek', function () { 157 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 158 | var dt2 = dt.toEndOfWeek(); 159 | 160 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 161 | ok(equalDates(dt2, new DateTime([2016, 10, 8, 23, 59, 59, 999]))); 162 | 163 | ok(dt2.format('dddd') === 'Saturday'); 164 | }); 165 | 166 | test('[TransformTo] toEndOfMonth', function () { 167 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 168 | var dt2 = dt.toEndOfMonth(); 169 | 170 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 171 | ok(equalDates(dt2, new DateTime([2016, 10, 31, 23, 59, 59, 999]))); 172 | 173 | dt = new DateTime([2016, 9, 5, 14, 54, 13, 555]); 174 | dt2 = dt.toEndOfMonth(); 175 | 176 | ok(equalDates(dt2, new DateTime([2016, 9, 30, 23, 59, 59, 999]))); 177 | 178 | dt = new DateTime([2016, 2, 5, 14, 54, 13, 555]); 179 | dt2 = dt.toEndOfMonth(); 180 | 181 | ok(equalDates(dt2, new DateTime([2016, 2, 29, 23, 59, 59, 999]))); 182 | 183 | dt = new DateTime([2017, 2, 5, 14, 54, 13, 555]); 184 | dt2 = dt.toEndOfMonth(); 185 | 186 | ok(equalDates(dt2, new DateTime([2017, 2, 28, 23, 59, 59, 999]))); 187 | }); 188 | 189 | test('[TransformTo] toEndOfYear', function () { 190 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555]); 191 | var dt2 = dt.toEndOfYear(); 192 | 193 | ok(equalDates(dt, new DateTime([2016, 10, 5, 14, 54, 13, 555]))); 194 | ok(equalDates(dt2, new DateTime([2016, 12, 31, 23, 59, 59, 999]))); 195 | }); 196 | 197 | /** 198 | * ---------------------------------------------------------------------------------------- 199 | * toSecond 200 | * ---------------------------------------------------------------------------------------- 201 | */ 202 | 203 | test('[TransformTo] toSecond :: UTC', function () { 204 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555], UTC_TIMEZONE); 205 | var second = dt.toSecond(); 206 | 207 | ok(second instanceof Second); 208 | ok(second.isEqual(new Second('2016-10-05T14:54:13', UTC_TIMEZONE))); 209 | }); 210 | 211 | test('[TransformTo] toSecond :: Timezone', function () { 212 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 213 | 214 | setTestTimezone({ 215 | abbr: ['TST'], 216 | dst: [false], 217 | offset: [-240], 218 | until: [null] 219 | }); 220 | 221 | var dt = new DateTime('2016-10-05T14:54:13.555', TEST_TIMEZONE); 222 | var second = dt.toSecond(); 223 | 224 | ok(second instanceof Second); 225 | ok(second.isEqual(new Second('2016-10-05T14:54:13', TEST_TIMEZONE))); 226 | }); 227 | 228 | /** 229 | * ---------------------------------------------------------------------------------------- 230 | * toMinute 231 | * ---------------------------------------------------------------------------------------- 232 | */ 233 | 234 | test('[TransformTo] toMinute :: UTC', function () { 235 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555], UTC_TIMEZONE); 236 | var minute = dt.toMinute(); 237 | 238 | ok(minute instanceof Minute); 239 | ok(minute.isEqual(new Minute('2016-10-05T14:54', UTC_TIMEZONE))); 240 | }); 241 | 242 | test('[TransformTo] toMinute :: Timezone', function () { 243 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 244 | 245 | setTestTimezone({ 246 | abbr: ['TST'], 247 | dst: [false], 248 | offset: [-240], 249 | until: [null] 250 | }); 251 | 252 | var dt = new DateTime('2016-10-05T14:54:13.555', TEST_TIMEZONE); 253 | var minute = dt.toMinute(); 254 | 255 | ok(minute instanceof Minute); 256 | ok(minute.isEqual(new Minute('2016-10-05T14:54', TEST_TIMEZONE))); 257 | }); 258 | 259 | /** 260 | * ---------------------------------------------------------------------------------------- 261 | * toHour 262 | * ---------------------------------------------------------------------------------------- 263 | */ 264 | 265 | test('[TransformTo] toHour :: UTC', function () { 266 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555], UTC_TIMEZONE); 267 | var hour = dt.toHour(); 268 | 269 | ok(hour instanceof Hour); 270 | ok(hour.isEqual(new Hour('2016-10-05T14', UTC_TIMEZONE))); 271 | }); 272 | 273 | test('[TransformTo] toHour :: Timezone', function () { 274 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 275 | 276 | setTestTimezone({ 277 | abbr: ['TST'], 278 | dst: [false], 279 | offset: [-240], 280 | until: [null] 281 | }); 282 | 283 | var dt = new DateTime('2016-10-05T14:54:13.555', TEST_TIMEZONE); 284 | var hour = dt.toHour(); 285 | 286 | ok(hour instanceof Hour); 287 | ok(hour.isEqual(new Hour('2016-10-05T14', TEST_TIMEZONE))); 288 | }); 289 | 290 | /** 291 | * ---------------------------------------------------------------------------------------- 292 | * toDay 293 | * ---------------------------------------------------------------------------------------- 294 | */ 295 | 296 | test('[TransformTo] toDay :: UTC', function () { 297 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555], UTC_TIMEZONE); 298 | var day = dt.toDay(); 299 | 300 | ok(day instanceof Day); 301 | ok(day.isEqual(new Day('2016-10-05', UTC_TIMEZONE))); 302 | }); 303 | 304 | test('[TransformTo] toDay :: Timezone', function () { 305 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 306 | 307 | setTestTimezone({ 308 | abbr: ['TST'], 309 | dst: [false], 310 | offset: [-240], 311 | until: [null] 312 | }); 313 | 314 | var dt = new DateTime('2016-10-05T14:54:13.555', TEST_TIMEZONE); 315 | var day = dt.toDay(); 316 | 317 | ok(day instanceof Day); 318 | ok(day.isEqual(new Day('2016-10-05', TEST_TIMEZONE))); 319 | }); 320 | 321 | /** 322 | * ---------------------------------------------------------------------------------------- 323 | * toWeek 324 | * ---------------------------------------------------------------------------------------- 325 | */ 326 | 327 | test('[TransformTo] toWeek :: UTC', function () { 328 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555], UTC_TIMEZONE); 329 | var week = dt.toWeek(); 330 | 331 | ok(week instanceof Week); 332 | ok(week.isEqual(new Week('2016-10-05', UTC_TIMEZONE))); 333 | }); 334 | 335 | test('[TransformTo] toWeek :: Timezone', function () { 336 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 337 | 338 | setTestTimezone({ 339 | abbr: ['TST'], 340 | dst: [false], 341 | offset: [-240], 342 | until: [null] 343 | }); 344 | 345 | var dt = new DateTime('2016-10-05T14:54:13.555', TEST_TIMEZONE); 346 | var week = dt.toWeek(); 347 | 348 | ok(week instanceof Week); 349 | ok(week.isEqual(new Week('2016-10-05', TEST_TIMEZONE))); 350 | }); 351 | 352 | /** 353 | * ---------------------------------------------------------------------------------------- 354 | * toMonth 355 | * ---------------------------------------------------------------------------------------- 356 | */ 357 | 358 | test('[TransformTo] toMonth :: UTC', function () { 359 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555], UTC_TIMEZONE); 360 | var month = dt.toMonth(); 361 | 362 | ok(month instanceof Month); 363 | ok(month.isEqual(new Month('2016-10', UTC_TIMEZONE))); 364 | }); 365 | 366 | test('[TransformTo] toMonth :: Timezone', function () { 367 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 368 | 369 | setTestTimezone({ 370 | abbr: ['TST'], 371 | dst: [false], 372 | offset: [-240], 373 | until: [null] 374 | }); 375 | 376 | var dt = new DateTime('2016-10-05T14:54:13.555', TEST_TIMEZONE); 377 | var month = dt.toMonth(); 378 | 379 | ok(month instanceof Month); 380 | ok(month.isEqual(new Month('2016-10', TEST_TIMEZONE))); 381 | }); 382 | 383 | /** 384 | * ---------------------------------------------------------------------------------------- 385 | * toMonthWeeks 386 | * ---------------------------------------------------------------------------------------- 387 | */ 388 | 389 | test('[TransformTo] toMonthWeeks :: UTC', function () { 390 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555], UTC_TIMEZONE); 391 | var monthWeeks = dt.toMonthWeeks(); 392 | 393 | ok(monthWeeks instanceof MonthWeeks); 394 | ok(monthWeeks.isEqual(new MonthWeeks('2016-10', UTC_TIMEZONE))); 395 | }); 396 | 397 | test('[TransformTo] toMonthWeeks :: Timezone', function () { 398 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 399 | 400 | setTestTimezone({ 401 | abbr: ['TST'], 402 | dst: [false], 403 | offset: [-240], 404 | until: [null] 405 | }); 406 | 407 | var dt = new DateTime('2016-10-05T14:54:13.555', TEST_TIMEZONE); 408 | var monthWeeks = dt.toMonthWeeks(); 409 | 410 | ok(monthWeeks instanceof MonthWeeks); 411 | ok(monthWeeks.isEqual(new MonthWeeks('2016-10', TEST_TIMEZONE))); 412 | }); 413 | 414 | /** 415 | * ---------------------------------------------------------------------------------------- 416 | * toYear 417 | * ---------------------------------------------------------------------------------------- 418 | */ 419 | 420 | test('[TransformTo] toYear :: UTC', function () { 421 | var dt = new DateTime([2016, 10, 5, 14, 54, 13, 555], UTC_TIMEZONE); 422 | var year = dt.toYear(); 423 | 424 | ok(year instanceof Year); 425 | ok(year.isEqual(new Year('2016', UTC_TIMEZONE))); 426 | }); 427 | 428 | test('[TransformTo] toYear :: Timezone', function () { 429 | DateTime.setDefaultTimezone(UTC_TIMEZONE); 430 | 431 | setTestTimezone({ 432 | abbr: ['TST'], 433 | dst: [false], 434 | offset: [-240], 435 | until: [null] 436 | }); 437 | 438 | var dt = new DateTime('2016-10-05T14:54:13.555', TEST_TIMEZONE); 439 | var year = dt.toYear(); 440 | 441 | ok(year instanceof Year); 442 | ok(year.isEqual(new Year('2016-10', TEST_TIMEZONE))); 443 | }); 444 | })(); 445 | --------------------------------------------------------------------------------