scripts/core/datetime/datetime.ts
import _ from 'lodash';
import {gettext} from 'core/utils';
import moment from 'moment-timezone';
import {appConfig} from 'appConfig';
import {IArticle} from 'superdesk-api';
const ISO_DATE_FORMAT = 'YYYY-MM-DD';
const ISO_WEEK_FORMAT = 'YYYY-W';
const ISO_YEAR_FORMAT = 'YYYY';
const LONG_FORMAT = appConfig.longDateFormat || 'LLL';
const TIME_FORMAT = appConfig.shortTimeFormat || 'hh:mm';
const DATE_FORMAT = appConfig.shortDateFormat || 'MM/DD';
const WEEK_FORMAT = appConfig.shortWeekFormat || 'dddd, ' + TIME_FORMAT;
const ARCHIVE_FORMAT = appConfig.ArchivedDateFormat || DATE_FORMAT;
const SERVER_FORMAT = 'YYYY-MM-DDTHH:mm:ssZZ';
/**
* Get long representation of given datetime
*
* @param {String} d iso format datetime
*/
export function longFormat(d: string | moment.Moment): string {
return moment(d).format(LONG_FORMAT);
}
export function serverFormat(d: string | moment.Moment): string {
return moment(d).utc().format(SERVER_FORMAT);
}
DateTimeDirective.$inject = ['datetime'];
function DateTimeDirective(datetime) {
return {
scope: {date: '=', fromNow: '='},
link: function datetimeLink(scope, elem) {
scope.$watch('date', renderDate);
/**
* Render relative date within given directive
*
* @param {string} date iso date
*/
function renderDate(date) {
var momentDate = moment(date);
var txt = scope.fromNow ? momentDate.fromNow() : datetime.shortFormat(momentDate);
elem.text(txt);
elem.attr('title', momentDate.format('LLLL'));
}
},
};
}
ShortDateDirective.$inject = [];
function ShortDateDirective() {
var CONFIG_DATE_FORMAT = appConfig.view.dateformat || appConfig.model.dateformat;
return {
scope: {date: '='},
link: function dateLink(scope, elem) {
scope.$watch('date', renderDate);
/**
* Render short date within given directive
*
* @param {string} date iso date
*/
function renderDate(date) {
var momentDate = moment(date);
var text = momentDate.format(CONFIG_DATE_FORMAT);
if (momentDate) {
elem.text(text);
elem.attr('title', text);
}
}
},
};
}
function isSameDay(a, b) {
return a.format(ISO_DATE_FORMAT) === b.format(ISO_DATE_FORMAT);
}
function isSameWeek(a, b) {
return a.format(ISO_WEEK_FORMAT) === b.format(ISO_WEEK_FORMAT);
}
function isArchiveYear(a, b) {
return (appConfig.ArchivedDateOnCalendarYear === 1) ?
a.format(ISO_YEAR_FORMAT) !== b.format(ISO_YEAR_FORMAT) : b.diff(a, 'years') >= 1;
}
export function isScheduled(__item: IArticle) {
const item = __item.archive_item ?? __item;
return item.publish_schedule != null;
}
/**
* Get date and time format for scheduled datetime
* Returns time for current day, date and time otherwise
*/
export function scheduledFormat(__item: IArticle): {short: string, long: string} {
const browserTimezone = moment.tz.guess();
const item = __item.archive_item ?? __item;
const datetime = item?.schedule_settings?.time_zone == null
? moment(item.publish_schedule).tz(browserTimezone)
: moment.tz(
item.publish_schedule.replace('+0000', ''),
item.schedule_settings.time_zone,
).tz(browserTimezone);
var now = moment();
const _date = datetime.format(appConfig.view.dateformat || 'MM/DD'),
_time = datetime.format(appConfig.view.timeformat || 'hh:mm');
let short = isSameDay(datetime, now) ? '@ '.concat(_time) : _date.concat(' @ ', _time);
return {
short: short,
long: longFormat(datetime),
};
}
DateTimeService.$inject = [];
function DateTimeService() {
/**
* Get short representation of given datetime
*
* It returns time for current day, day + time for current week, date otherwise.
*
* @param {String} d iso format datetime
* @return {String}
*/
this.shortFormat = function(d) {
var m = moment(d);
var now = moment();
if (isSameDay(m, now)) {
return m.format(TIME_FORMAT);
} else if (isSameWeek(m, now)) {
return m.format(WEEK_FORMAT);
} else if (isArchiveYear(m, now)) {
return m.format(ARCHIVE_FORMAT);
}
return m.format(DATE_FORMAT);
};
this.longFormat = longFormat;
}
DateTimeHelperService.$inject = [];
function DateTimeHelperService() {
/*
* @param timestring 2016-03-01T04:45:00+0000
* @param timezone Europe/London
*/
this.splitDateTime = function(timestring, timezone) {
var momentTS = moment.tz(timestring, timezone);
return {
date: momentTS.format(appConfig.model.dateformat),
time: momentTS.format(appConfig.model.timeformat),
};
};
this.isValidTime = function(value, format) {
var timeFormat = format || appConfig.model.timeformat;
return moment(value, timeFormat, true).isValid();
};
this.isValidDate = function(value, format) {
var dateFormat = format || appConfig.model.dateformat;
return moment(value, dateFormat, true).isValid();
};
this.mergeDateTime = function(dateStr, timeStr, timezone) {
var tz = timezone || appConfig.default_timezone;
var mergeStr = dateStr + ' ' + timeStr;
var formatter = appConfig.model.dateformat + ' ' + appConfig.model.timeformat;
// return without timezone information, which is stored separately
return moment.tz(mergeStr, formatter, tz).format('YYYY-MM-DD[T]HH:mm:ss');
};
/*
* @param timestring 2016-03-01T04:45:00+0000.
*/
this.greaterThanUTC = function(timestring) {
return moment(timestring, 'YYYY-MM-DDTHH:mm:ssZZ') > moment.utc();
};
/**
* Remove tz info from given datetime
*
* it's added automatically on server for every datetime like values
*
* @param {String} datetime
* @return {String}
*/
this.removeTZ = function(datetime) {
if (datetime) {
return datetime.replace('+0000', '').replace('+00:00', '');
}
};
}
/**
* @ngdoc module
* @module superdesk.core.datetime
* @name superdesk.core.datetime
* @packageName superdesk.core
* @description Superdesk core date & time module.
*/
export default angular.module('superdesk.core.datetime', [
'superdesk.config',
'ngResource',
'superdesk.core.datetime.absdate',
'superdesk.core.datetime.groupdates',
'superdesk.core.datetime.relativeDate',
'superdesk.core.datetime.reldatecomplex',
'superdesk.core.datetime.reldate',
'superdesk.core.translate',
])
.directive('sdDatetime', DateTimeDirective)
.directive('sdShortDate', ShortDateDirective)
.filter('reldate', function reldateFactory() {
return function reldate(date) {
return moment(date).fromNow();
};
})
/**
* Returns the difference between given date and the
* current datetime in hours
*
* @param {Datetime} date iso format datetime
* @return {Int} hours
*/
.filter('hoursFromNow', function hoursFromNowFactory() {
return function hoursFromNow(date) {
var difference = moment().diff(moment(date));
var d = moment.duration(difference);
var s = Math.floor(d.asHours());
return s;
};
})
// format datetime obj to time string
.filter('time', function timeFilterFactory() {
var CONFIG_TIME_FORMAT = appConfig.view == null || appConfig.view.timeformat == null
? 'h:mm'
: appConfig.view.timeformat;
return function timeFilter(time) {
var m = moment(time, 'HH:mm:ss');
return m.format(CONFIG_TIME_FORMAT);
};
})
.constant('moment', moment)
.factory('weekdays', [function() {
return Object.freeze({
MON: gettext('Monday'),
TUE: gettext('Tuesday'),
WED: gettext('Wednesday'),
THU: gettext('Thursday'),
FRI: gettext('Friday'),
SAT: gettext('Saturday'),
SUN: gettext('Sunday'),
});
}])
/**
* A service that automatically fetches the time zone data from the
* server upon instantiaton and stores it internally for future use,
* avoiding the need to fetch it again every time when needed.
*/
.factory('tzdata', ['$resource', function($resource) {
const tzResource = $resource('scripts/apps/dashboard/world-clock/timezones-all.json');
/**
* Returns a sorted list of all time zone names. If time zone data
* has not yet been fetched from the server, an empty list is
* returned.
* To determine whether or not the data has been fetched yet, the
* $promise property should be examined.
*
* @method getTzNames
* @return {Array} a list of time zone names
*/
tzResource.prototype.getTzNames = function() {
return _.union(
_.keys(this.zones),
_.keys(this.links),
).sort();
};
// return an array that will contain the fetched data when
// it arrives from the server
return tzResource.get();
}])
.service('datetime', DateTimeService)
.service('datetimeHelper', DateTimeHelperService);