/**
* @namespace Date
*/
const LOCAL_FORMAT_YMD = ['AF', 'CN', 'HU', 'JP', 'KP', 'KR', 'LT', 'MN', 'TW'];
const LOCAL_FORMAT_MDY = ['BZ', 'FM', 'US'];
/**
* Second in milliseconds
*
* @memberof Date
* @constant
* @type {number}
*/
var SECOND = 1000;
/**
* Minute in milliseconds
*
* @memberof Date
* @constant
* @type {number}
*/
var MINUTE = 60 * SECOND;
/**
* Hour in milliseconds
*
* @memberof Date
* @constant
* @type {number}
*/
var HOUR = 60 * MINUTE;
/**
* Day in milliseconds
*
* @memberof Date
* @constant
* @type {number}
*/
var DAY = 24 * HOUR;
/**
* Week in milliseconds
*
* @memberof Date
* @constant
* @type {number}
*/
var WEEK = 7 * DAY;
/**
* Today in milliseconds
*
* @memberof Date
* @constant
* @type {number}
*/
function TODAY() {
return DAY * Math.floor( Date.now() / DAY );
}
/**
* Yesterday in milliseconds
*
* @memberof Date
* @constant
* @type {number}
*/
function YESTERDAY() {
return Date.TODAY - DAY;
}
/**
* Tomorrow in milliseconds
*
* @memberof Date
* @constant
* @type {number}
*/
function TOMORROW() {
return Date.TODAY + DAY;
}
/**
* Day after tomorrow in milliseconds
*
* @memberof Date
* @constant
* @type {number}
*/
function DAYAFTERTOMORROW() {
return Date.TOMORROW + DAY;
}
/**
* Return new Date instance from given value
*
* It's simmilar to native Date.parse, but you can use such strings like:
* 'today', 'yesterday', 'tomorrow', 'dayaftertomorrow', 'now'
*
* Feel free to contribute if you think that this method should support even more!
*
* @memberof Date
* @param {string|number|Date} value Value to be parsed
* @throws Will throw an error if the value is not supported.
* @returns {Date} New Date
*/
function parseValue(value) {
var type = typeof value;
if(type === 'string') {
switch(value.toLowerCase()) {
case 'today' :
return new Date(Date.TODAY);
case 'yesterday' :
return new Date(Date.YESTERDAY);
case 'tomorrow' :
return new Date(Date.TOMORROW);
case 'dayaftertomorrow' :
return new Date(Date.DAYAFTERTOMORROW);
case 'now' :
return new Date();
default :
throw new Error('Unsupported string: ' + value);
}
} else if(type === 'number' || value instanceof Date) {
return new Date(value);
} else {
throw new TypeError('Unsupported value type');
}
}
/**
* Return timestamp of now + days
*
* @memberof Date
* @param {number} days Number of days difference
* @returns {number} Timestamp
*/
function daysFromNow(days) {
return Date.now() + Date.DAY * days;
}
/**
* Get local date format
*
* @memberof Date
* @param {boolean} [fullFormat=true] Flag if it should be full date format like dd.mm.yyyy instead d.m.y
* @returns {string} Local date format
*/
function getLocalDateFormat(fullFormat) {
let countryCode, format;
if(typeof fullFormat === 'undefined') {
fullFormat = true;
}
countryCode = global.getCountry() || 'US';
if(LOCAL_FORMAT_YMD.indexOf(countryCode) >= 0) {
format = 'y-m-d';
} else if(LOCAL_FORMAT_MDY.indexOf(countryCode) >= 0) {
format = 'm/d/y';
} else {
format = 'd.m.y';
}
if(fullFormat) {
format = format.replace('d', 'dd');
format = format.replace('m', 'mm');
format = format.replace('y', 'yyyy');
}
return format;
}
/**
* Get timezone name
*
* @memberof Date
* @returns {string} Timezone
*/
function getTimezoneName() {
return new this().toString().match(/\(([^)]+)\)$/)[1];
}
/**
* Returns object with time parts
*
* @memberof Date
* @example
* // returns { h: 0, m: 1, s: 1, ms: 500 }
* Date.getHms(61500)
* @param {number} time Time to be used
* @returns {Object} Time in stopwatch format
*/
function getHms(time) {
var obj = {
h: 0,
m: 0,
s: 0,
ms: 0
};
obj.ms = Math.max(0, time % 1000);
time -= obj.ms;
time /= 1000;
obj.s = Math.max(0, time % 60);
time -= obj.s;
time /= 60;
obj.m = Math.max(0, time % 60);
time -= obj.m;
time /= 60;
obj.h = Math.max(0, time);
return obj;
}
/**
* Returns given time (in milliseconds) in HMS format
*
* @memberof Date
* @example
* // returns '1m 5s'
* Date.toHmsFormat(61500)
* @param {number} time Time to be converted
* @param {string} [accuracy=seconds] Accuracy
* @returns {string} Time in HMS format
*/
function toHmsFormat(time, accuracy) {
if(typeof accuracy === 'undefined') {
accuracy = 'seconds';
}
var obj = Date.getHms(time);
var ret = [];
switch(accuracy) {
case 'hours':
ret.push(obj.h + 'h');
break;
case 'minutes':
if(obj.h > 0) {
ret.push(obj.h + 'h');
}
ret.push(obj.m + 'm');
break;
case 'seconds':
if(obj.h > 0) {
ret.push(obj.h + 'h');
}
if(obj.m > 0) {
ret.push(obj.m + 'm');
}
ret.push(obj.s + 's');
break;
default:
throw new TypeError('Unknown accuracy');
}
return ret.join(' ');
}
/**
* Returns given time (in milliseconds) in stopwatch format - [HH:]MM:SS.XXX
*
* @memberof Date
* @example
* // returns '01:01.5'
* Date.toStopwatchFormat(61500)
* @param {number} time Time to be converted
* @returns {string} Time in stopwatch format
*/
function toStopwatchFormat(time) {
var obj = Date.getHms(time);
var ret = obj.m.pad(2) + ':' + obj.s.pad(2) + '.' + Math.floor(obj.ms / 100);
if(obj.h > 0) {
ret = obj.h.pad(2) + ':' + ret;
}
return ret;
}
/**
* Returns given time (in milliseconds) in timer format - [HH:]MM:SS
*
* @memberof Date
* @example
* // returns '01:01'
* Date.toStopwatchFormat(61500)
* @param {number} time Time to be converted
* @returns {string} Time in timer format
*/
function toTimerFormat(time) {
var obj = Date.getHms(time);
var ret = obj.m.pad(2) + ':' + obj.s.pad(2);
if(obj.h > 0) {
ret = obj.h.pad(2) + ':' + ret;
}
return ret;
}
/**
* Return number of days passed between this Date and given in argument
*
* @memberof Date.prototype
* @param {(Date|string|number)} [toDate=now] Proper date
* @returns {number} Number of days passed
*/
function daysPassed(toDate) {
var toDateType = typeof toDate;
if(toDateType === 'undefined') {
toDate = new Date();
} else if(toDateType === 'number' || toDateType === 'string') {
toDate = new Date(toDate);
}
if(!(toDate instanceof Date)) {
throw new TypeError('toDate is not instance of Date');
}
return Math.floor(Math.abs((this.getTime() - toDate.getTime()) / Date.DAY));
}
/**
* Returns this Date in custom date format
*
* @memberof Date.prototype
* @param {string} format String representing date format
* @returns {string} Date string
*/
function toCustomDate(format) {
format = format.replace('d', this.getDate().pad(2));
format = format.replace('m', (this.getMonth() + 1).pad(2));
format = format.replace('y', this.getFullYear());
return format;
}
/**
* Returns this Date in UI time string
*
* @memberof Date.prototype
* @param {boolean} [showSeconds=true] Flag if seconds also should be returned
* @returns {string} Time string
*/
function toUiTime(showSeconds = true) {
const seconds = showSeconds ? `:${this.getSeconds().pad(2)}` : '';
return this.getHours().pad(2) + ':' + this.getMinutes().pad(2) + seconds;
}
/**
* Returns this Date in UI date string
*
* @memberof Date.prototype
* @see Date#getLocalDateFormat
* @returns {string} Date string
*/
function toUiDate() {
return this.toCustomDate(Date.getLocalDateFormat(false));
}
/**
* Returns this Date in UI datetime string
*
* @memberof Date.prototype
* @param {boolean} [showSeconds=true] Flag if seconds also should be returned
* @returns {string} Time string
*/
function toUiDateTime(showSeconds = true) {
return this.toUiDate() + ' ' + this.toUiTime(showSeconds);
}
/**
* Returns this Date in form inputs time string
*
* @memberof Date.prototype
* @returns {string} Time string
*/
function toInputTimeFormat() {
return this.toUiTime(false);
}
/**
* Returns this Date in forms input date string
*
* @memberof Date.prototype
* @returns {string} Date string
*/
function toInputDateFormat() {
return this.toCustomDate('y-m-d');
}
/**
* Add time to this Date
*
* @memberof Date.prototype
* @param {number} time Time to add
* @returns {number} New timestamp of this Date
*/
function addTime(time) {
return this.setTime(this.getTime() + time );
}
export default {
constant: {
SECOND,
MINUTE,
HOUR,
DAY,
WEEK
},
getter: {
TODAY,
YESTERDAY,
TOMORROW,
DAYAFTERTOMORROW
},
static: {
parseValue,
daysFromNow,
getLocalDateFormat,
getTimezoneName,
getHms,
toHmsFormat,
toStopwatchFormat,
toTimerFormat
},
method: {
daysPassed,
toCustomDate,
toUiTime,
toUiDate,
toUiDateTime,
toInputTimeFormat,
toInputDateFormat,
addTime
}
};