forked from EVOgeek/Vmeda.Online
373 lines
12 KiB
TypeScript
373 lines
12 KiB
TypeScript
// (C) Copyright 2015 Moodle Pty Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { Injectable } from '@angular/core';
|
|
|
|
import moment, { LongDateFormatKey } from 'moment';
|
|
import { CoreConstants } from '@/core/constants';
|
|
import { makeSingleton, Translate } from '@singletons';
|
|
|
|
/*
|
|
* "Utils" service with helper functions for date and time.
|
|
*/
|
|
@Injectable({ providedIn: 'root' })
|
|
export class CoreTimeUtilsProvider {
|
|
|
|
protected static readonly FORMAT_REPLACEMENTS = { // To convert PHP strf format to Moment format.
|
|
'%a': 'ddd',
|
|
'%A': 'dddd',
|
|
'%d': 'DD',
|
|
'%e': 'D', // Not exactly the same. PHP adds a space instead of leading zero, Moment doesn't.
|
|
'%j': 'DDDD',
|
|
'%u': 'E',
|
|
'%w': 'e', // It might not behave exactly like PHP, the first day could be calculated differently.
|
|
'%U': 'ww', // It might not behave exactly like PHP, the first week could be calculated differently.
|
|
'%V': 'WW',
|
|
'%W': 'ww', // It might not behave exactly like PHP, the first week could be calculated differently.
|
|
'%b': 'MMM',
|
|
'%B': 'MMMM',
|
|
'%h': 'MMM',
|
|
'%m': 'MM',
|
|
'%C' : '', // Not supported by Moment.
|
|
'%g': 'GG',
|
|
'%G': 'GGGG',
|
|
'%y': 'YY',
|
|
'%Y': 'YYYY',
|
|
'%H': 'HH',
|
|
'%k': 'H', // Not exactly the same. PHP adds a space instead of leading zero, Moment doesn't.
|
|
'%I': 'hh',
|
|
'%l': 'h', // Not exactly the same. PHP adds a space instead of leading zero, Moment doesn't.
|
|
'%M': 'mm',
|
|
'%p': 'A',
|
|
'%P': 'a',
|
|
'%r': 'hh:mm:ss A',
|
|
'%R': 'HH:mm',
|
|
'%S': 'ss',
|
|
'%T': 'HH:mm:ss',
|
|
'%X': 'LTS',
|
|
'%z': 'ZZ',
|
|
'%Z': 'ZZ', // Not supported by Moment, it was deprecated. Use the same as %z.
|
|
'%c': 'LLLL',
|
|
'%D': 'MM/DD/YY',
|
|
'%F': 'YYYY-MM-DD',
|
|
'%s': 'X',
|
|
'%x': 'L',
|
|
'%n': '\n',
|
|
'%t': '\t',
|
|
'%%': '%',
|
|
};
|
|
|
|
/**
|
|
* Convert a PHP format to a Moment format.
|
|
*
|
|
* @param format PHP format.
|
|
* @return Converted format.
|
|
*/
|
|
convertPHPToMoment(format: string): string {
|
|
if (typeof format != 'string') {
|
|
// Not valid.
|
|
return '';
|
|
}
|
|
|
|
let converted = '';
|
|
let escaping = false;
|
|
|
|
for (let i = 0; i < format.length; i++) {
|
|
let char = format[i];
|
|
|
|
if (char == '%') {
|
|
// It's a PHP format, try to convert it.
|
|
i++;
|
|
char += format[i] || '';
|
|
|
|
if (escaping) {
|
|
// We were escaping some characters, stop doing it now.
|
|
escaping = false;
|
|
converted += ']';
|
|
}
|
|
|
|
converted += typeof CoreTimeUtilsProvider.FORMAT_REPLACEMENTS[char] != 'undefined' ?
|
|
CoreTimeUtilsProvider.FORMAT_REPLACEMENTS[char] : char;
|
|
} else {
|
|
// Not a PHP format. We need to escape them, otherwise the letters could be confused with Moment formats.
|
|
if (!escaping) {
|
|
escaping = true;
|
|
converted += '[';
|
|
}
|
|
|
|
converted += char;
|
|
}
|
|
}
|
|
|
|
if (escaping) {
|
|
// Finish escaping.
|
|
converted += ']';
|
|
}
|
|
|
|
return converted;
|
|
}
|
|
|
|
/**
|
|
* Fix format to use in an ion-datetime.
|
|
*
|
|
* @param format Format to use.
|
|
* @return Fixed format.
|
|
*/
|
|
fixFormatForDatetime(format: string): string {
|
|
if (!format) {
|
|
return '';
|
|
}
|
|
|
|
// The component ion-datetime doesn't support escaping characters ([]), so we remove them.
|
|
let fixed = format.replace(/[[\]]/g, '');
|
|
|
|
if (fixed.indexOf('A') != -1) {
|
|
// Do not use am/pm format because there is a bug in ion-datetime.
|
|
fixed = fixed.replace(/ ?A/g, '');
|
|
fixed = fixed.replace(/h/g, 'H');
|
|
}
|
|
|
|
return fixed;
|
|
}
|
|
|
|
/**
|
|
* Returns hours, minutes and seconds in a human readable format
|
|
*
|
|
* @param seconds A number of seconds
|
|
* @return Seconds in a human readable format.
|
|
*/
|
|
formatTime(seconds: number): string {
|
|
const totalSecs = Math.abs(seconds);
|
|
const years = Math.floor(totalSecs / CoreConstants.SECONDS_YEAR);
|
|
let remainder = totalSecs - (years * CoreConstants.SECONDS_YEAR);
|
|
const days = Math.floor(remainder / CoreConstants.SECONDS_DAY);
|
|
|
|
remainder = totalSecs - (days * CoreConstants.SECONDS_DAY);
|
|
|
|
const hours = Math.floor(remainder / CoreConstants.SECONDS_HOUR);
|
|
remainder = remainder - (hours * CoreConstants.SECONDS_HOUR);
|
|
|
|
const mins = Math.floor(remainder / CoreConstants.SECONDS_MINUTE);
|
|
const secs = remainder - (mins * CoreConstants.SECONDS_MINUTE);
|
|
|
|
const ss = Translate.instance.instant('core.' + (secs == 1 ? 'sec' : 'secs'));
|
|
const sm = Translate.instance.instant('core.' + (mins == 1 ? 'min' : 'mins'));
|
|
const sh = Translate.instance.instant('core.' + (hours == 1 ? 'hour' : 'hours'));
|
|
const sd = Translate.instance.instant('core.' + (days == 1 ? 'day' : 'days'));
|
|
const sy = Translate.instance.instant('core.' + (years == 1 ? 'year' : 'years'));
|
|
let oyears = '';
|
|
let odays = '';
|
|
let ohours = '';
|
|
let omins = '';
|
|
let osecs = '';
|
|
|
|
if (years) {
|
|
oyears = years + ' ' + sy;
|
|
}
|
|
if (days) {
|
|
odays = days + ' ' + sd;
|
|
}
|
|
if (hours) {
|
|
ohours = hours + ' ' + sh;
|
|
}
|
|
if (mins) {
|
|
omins = mins + ' ' + sm;
|
|
}
|
|
if (secs) {
|
|
osecs = secs + ' ' + ss;
|
|
}
|
|
|
|
if (years) {
|
|
return oyears + ' ' + odays;
|
|
}
|
|
if (days) {
|
|
return odays + ' ' + ohours;
|
|
}
|
|
if (hours) {
|
|
return ohours + ' ' + omins;
|
|
}
|
|
if (mins) {
|
|
return omins + ' ' + osecs;
|
|
}
|
|
if (secs) {
|
|
return osecs;
|
|
}
|
|
|
|
return Translate.instance.instant('core.now');
|
|
}
|
|
|
|
/**
|
|
* Returns hours, minutes and seconds in a human readable format.
|
|
*
|
|
* @param duration Duration in seconds
|
|
* @param precision Number of elements to have in precision. 0 or undefined to full precission.
|
|
* @return Duration in a human readable format.
|
|
*/
|
|
formatDuration(duration: number, precision?: number): string {
|
|
precision = precision || 5;
|
|
|
|
const eventDuration = moment.duration(duration, 'seconds');
|
|
let durationString = '';
|
|
|
|
if (precision && eventDuration.years() > 0) {
|
|
durationString += ' ' + moment.duration(eventDuration.years(), 'years').humanize();
|
|
precision--;
|
|
}
|
|
if (precision && eventDuration.months() > 0) {
|
|
durationString += ' ' + moment.duration(eventDuration.months(), 'months').humanize();
|
|
precision--;
|
|
}
|
|
if (precision && eventDuration.days() > 0) {
|
|
durationString += ' ' + moment.duration(eventDuration.days(), 'days').humanize();
|
|
precision--;
|
|
}
|
|
if (precision && eventDuration.hours() > 0) {
|
|
durationString += ' ' + moment.duration(eventDuration.hours(), 'hours').humanize();
|
|
precision--;
|
|
}
|
|
if (precision && eventDuration.minutes() > 0) {
|
|
durationString += ' ' + moment.duration(eventDuration.minutes(), 'minutes').humanize();
|
|
precision--;
|
|
}
|
|
|
|
return durationString.trim();
|
|
}
|
|
|
|
/**
|
|
* Returns duration in a short human readable format: minutes and seconds, in fromat: 3' 27''.
|
|
*
|
|
* @param duration Duration in seconds
|
|
* @return Duration in a short human readable format.
|
|
*/
|
|
formatDurationShort(duration: number): string {
|
|
const minutes = Math.floor(duration / 60);
|
|
const seconds = duration - minutes * 60;
|
|
const durations = <string[]>[];
|
|
|
|
if (minutes > 0) {
|
|
durations.push(minutes + '\'');
|
|
}
|
|
|
|
if (seconds > 0 || minutes === 0) {
|
|
durations.push(seconds + '\'\'');
|
|
}
|
|
|
|
return durations.join(' ');
|
|
}
|
|
|
|
/**
|
|
* Return the current timestamp in a "readable" format: YYYYMMDDHHmmSS.
|
|
*
|
|
* @return The readable timestamp.
|
|
*/
|
|
readableTimestamp(): string {
|
|
return moment(Date.now()).format('YYYYMMDDHHmmSS');
|
|
}
|
|
|
|
/**
|
|
* Return the current timestamp (UNIX format, seconds).
|
|
*
|
|
* @return The current timestamp in seconds.
|
|
*/
|
|
timestamp(): number {
|
|
return Math.round(Date.now() / 1000);
|
|
}
|
|
|
|
/**
|
|
* Convert a timestamp into a readable date.
|
|
*
|
|
* @param timestamp Timestamp in milliseconds.
|
|
* @param format The format to use (lang key). Defaults to core.strftimedaydatetime.
|
|
* @param convert If true (default), convert the format from PHP to Moment. Set it to false for Moment formats.
|
|
* @param fixDay If true (default) then the leading zero from %d is removed.
|
|
* @param fixHour If true (default) then the leading zero from %I is removed.
|
|
* @return Readable date.
|
|
*/
|
|
userDate(timestamp: number, format?: string, convert: boolean = true, fixDay: boolean = true, fixHour: boolean = true): string {
|
|
format = Translate.instance.instant(format ? format : 'core.strftimedaydatetime');
|
|
|
|
if (fixDay) {
|
|
format = format!.replace(/%d/g, '%e');
|
|
}
|
|
|
|
if (fixHour) {
|
|
format = format!.replace('%I', '%l');
|
|
}
|
|
|
|
// Format could be in PHP format, convert it to moment.
|
|
if (convert) {
|
|
format = this.convertPHPToMoment(format!);
|
|
}
|
|
|
|
return moment(timestamp).format(format);
|
|
}
|
|
|
|
/**
|
|
* Convert a timestamp to the format to set to a datetime input.
|
|
*
|
|
* @param timestamp Timestamp to convert (in ms). If not provided, current time.
|
|
* @return Formatted time.
|
|
*/
|
|
toDatetimeFormat(timestamp?: number): string {
|
|
timestamp = timestamp || Date.now();
|
|
|
|
return this.userDate(timestamp, 'YYYY-MM-DDTHH:mm:ss.SSS', false) + 'Z';
|
|
}
|
|
|
|
/**
|
|
* Convert a text into user timezone timestamp.
|
|
*
|
|
* @param date To convert to timestamp.
|
|
* @return Converted timestamp.
|
|
*/
|
|
convertToTimestamp(date: string): number {
|
|
if (typeof date == 'string' && date.slice(-1) == 'Z') {
|
|
return moment(date).unix() - (moment().utcOffset() * 60);
|
|
}
|
|
|
|
return moment(date).unix();
|
|
}
|
|
|
|
/**
|
|
* Return the localized ISO format (i.e DDMMYY) from the localized moment format. Useful for translations.
|
|
* DO NOT USE this function for ion-datetime format. Moment escapes characters with [], but ion-datetime doesn't support it.
|
|
*
|
|
* @param localizedFormat Format to use.
|
|
* @return Localized ISO format
|
|
*/
|
|
getLocalizedDateFormat(localizedFormat: LongDateFormatKey): string {
|
|
return moment.localeData().longDateFormat(localizedFormat);
|
|
}
|
|
|
|
/**
|
|
* For a given timestamp get the midnight value in the user's timezone.
|
|
*
|
|
* The calculation is performed relative to the user's midnight timestamp
|
|
* for today to ensure that timezones are preserved.
|
|
*
|
|
* @param timestamp The timestamp to calculate from. If not defined, return today's midnight.
|
|
* @return The midnight value of the user's timestamp.
|
|
*/
|
|
getMidnightForTimestamp(timestamp?: number): number {
|
|
if (timestamp) {
|
|
return moment(timestamp * 1000).startOf('day').unix();
|
|
} else {
|
|
return moment().startOf('day').unix();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
export class CoreTimeUtils extends makeSingleton(CoreTimeUtilsProvider) {}
|