|
|
|
/*
|
|
|
|
* https://github.com/morethanwords/tweb
|
|
|
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
|
|
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { MOUNT_CLASS_TO } from "../config/debug";
|
|
|
|
import I18n, { i18n } from "../lib/langPack";
|
|
|
|
import { capitalizeFirstLetter } from "./string";
|
|
|
|
import tsNow from './tsNow';
|
|
|
|
|
|
|
|
export const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
|
|
export const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
|
|
|
|
|
|
export const ONE_DAY = 86400;
|
|
|
|
|
|
|
|
// https://stackoverflow.com/a/6117889
|
|
|
|
export const getWeekNumber = (date: Date) => {
|
|
|
|
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
|
|
|
const dayNum = d.getUTCDay() || 7;
|
|
|
|
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
|
|
|
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
|
|
|
return Math.ceil((((d.getTime() - yearStart.getTime()) / ONE_DAY) + 1) / 7);
|
|
|
|
};
|
|
|
|
|
|
|
|
export function formatDateAccordingToTodayNew(time: Date) {
|
|
|
|
const today = new Date();
|
|
|
|
const now = today.getTime() / 1000 | 0;
|
|
|
|
const timestamp = time.getTime() / 1000 | 0;
|
|
|
|
|
|
|
|
const options: Intl.DateTimeFormatOptions = {};
|
|
|
|
if((now - timestamp) < ONE_DAY && today.getDate() === time.getDate()) { // if the same day
|
|
|
|
options.hour = options.minute = '2-digit';
|
|
|
|
} else if(today.getFullYear() !== time.getFullYear()) { // different year
|
|
|
|
options.year = options.day = 'numeric';
|
|
|
|
options.month = '2-digit';
|
|
|
|
} else if((now - timestamp) < (ONE_DAY * 7) && getWeekNumber(today) === getWeekNumber(time)) { // current week
|
|
|
|
options.weekday = 'short';
|
|
|
|
} else { // same year
|
|
|
|
options.month = 'short';
|
|
|
|
options.day = 'numeric';
|
|
|
|
}
|
|
|
|
|
|
|
|
return new I18n.IntlDateElement({
|
|
|
|
date: time,
|
|
|
|
options
|
|
|
|
}).element;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function formatFullSentTime(timestamp: number) {
|
|
|
|
const date = new Date();
|
|
|
|
const time = new Date(timestamp * 1000);
|
|
|
|
const now = date.getTime() / 1000;
|
|
|
|
|
|
|
|
const timeEl = formatTime(time);
|
|
|
|
|
|
|
|
let dateEl: Node | string;
|
|
|
|
if((now - timestamp) < ONE_DAY && date.getDate() === time.getDate()) { // if the same day
|
|
|
|
dateEl = i18n('Date.Today');
|
|
|
|
} else if((now - timestamp) < (ONE_DAY * 2) && (date.getDate() - 1) === time.getDate()) { // yesterday
|
|
|
|
dateEl = capitalizeFirstLetter(I18n.format('Yesterday', true));
|
|
|
|
} else if(date.getFullYear() !== time.getFullYear()) { // different year
|
|
|
|
dateEl = new I18n.IntlDateElement({
|
|
|
|
date: time,
|
|
|
|
options: {
|
|
|
|
month: 'short',
|
|
|
|
day: 'numeric',
|
|
|
|
year: 'numeric'
|
|
|
|
}
|
|
|
|
}).element;
|
|
|
|
// dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate() + ', ' + time.getFullYear();
|
|
|
|
} else {
|
|
|
|
dateEl = new I18n.IntlDateElement({
|
|
|
|
date: time,
|
|
|
|
options: {
|
|
|
|
month: 'short',
|
|
|
|
day: 'numeric'
|
|
|
|
}
|
|
|
|
}).element;
|
|
|
|
// dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate();
|
|
|
|
}
|
|
|
|
|
|
|
|
const fragment = document.createDocumentFragment();
|
|
|
|
fragment.append(dateEl, ' ', i18n('ScheduleController.at'), ' ', timeEl);
|
|
|
|
return fragment;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function formatTime(date: Date) {
|
|
|
|
return new I18n.IntlDateElement({
|
|
|
|
date,
|
|
|
|
options: {
|
|
|
|
hour: '2-digit',
|
|
|
|
minute: '2-digit'
|
|
|
|
}
|
|
|
|
}).element;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.formatDateAccordingToTodayNew = formatDateAccordingToTodayNew);
|
|
|
|
|
|
|
|
export const getFullDate = (date: Date, options: Partial<{
|
|
|
|
noTime: true,
|
|
|
|
noSeconds: true,
|
|
|
|
monthAsNumber: true,
|
|
|
|
leadingZero: true
|
|
|
|
}> = {}) => {
|
|
|
|
const joiner = options.monthAsNumber ? '.' : ' ';
|
|
|
|
const time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + (options.noSeconds ? '' : ':' + ('0' + date.getSeconds()).slice(-2));
|
|
|
|
|
|
|
|
return (options.leadingZero ? ('0' + date.getDate()).slice(-2) : date.getDate()) +
|
|
|
|
joiner + (options.monthAsNumber ? ('0' + (date.getMonth() + 1)).slice(-2) : months[date.getMonth()]) +
|
|
|
|
joiner + date.getFullYear() +
|
|
|
|
(options.noTime ? '' : ', ' + time);
|
|
|
|
};
|
|
|
|
|
|
|
|
export {tsNow};
|
|
|
|
|
|
|
|
// https://github.com/DrKLO/Telegram/blob/d52b2c921abd3c1e8d6368858313ad0cb0468c07/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java
|
|
|
|
const minYear = 2013;
|
|
|
|
const yearPattern = new RegExp("20[0-9]{1,2}");
|
|
|
|
const monthYearOrDayPattern = new RegExp("(\\w{3,}) ([0-9]{0,4})", 'i');
|
|
|
|
const yearOrDayAndMonthPattern = new RegExp("([0-9]{0,4}) (\\w{2,})", 'i');
|
|
|
|
const shortDate = new RegExp("^([0-9]{1,4})(\\.| |/|\\-)([0-9]{1,4})$", 'i');
|
|
|
|
const longDate = new RegExp("^([0-9]{1,2})(\\.| |/|\\-)([0-9]{1,2})(\\.| |/|\\-)([0-9]{1,4})$", 'i');
|
|
|
|
const numberOfDaysEachMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
|
|
export type DateData = {
|
|
|
|
title: string,
|
|
|
|
minDate: number,
|
|
|
|
maxDate: number,
|
|
|
|
};
|
|
|
|
export function fillTipDates(query: string, dates: DateData[]) {
|
|
|
|
const q = query.trim().toLowerCase();
|
|
|
|
|
|
|
|
if(q.length < 3) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if("today".indexOf(q) === 0) {
|
|
|
|
const date = new Date();
|
|
|
|
const year = date.getFullYear();
|
|
|
|
const month = date.getMonth();
|
|
|
|
const day = date.getDate();
|
|
|
|
date.setFullYear(year, month, day);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const minDate = date.getTime();
|
|
|
|
date.setFullYear(year, month, day + 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const maxDate = date.getTime() - 1;
|
|
|
|
dates.push({
|
|
|
|
title: 'Today',
|
|
|
|
minDate,
|
|
|
|
maxDate
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if("yesterday".indexOf(q) === 0) {
|
|
|
|
const date = new Date();
|
|
|
|
const year = date.getFullYear();
|
|
|
|
const month = date.getMonth();
|
|
|
|
const day = date.getDate();
|
|
|
|
date.setFullYear(year, month, day);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const minDate = date.getTime() - 86400000;
|
|
|
|
date.setFullYear(year, month, day + 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const maxDate = date.getTime() - 86400001;
|
|
|
|
dates.push({
|
|
|
|
title: 'Yesterday',
|
|
|
|
minDate,
|
|
|
|
maxDate
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const dayOfWeek = getDayOfWeek(q);
|
|
|
|
if(dayOfWeek >= 0) {
|
|
|
|
const date = new Date();
|
|
|
|
const now = date.getTime();
|
|
|
|
const currentDay = date.getDay();
|
|
|
|
const distance = dayOfWeek - currentDay;
|
|
|
|
date.setDate(date.getDate() + distance);
|
|
|
|
if(date.getTime() > now) {
|
|
|
|
date.setTime(date.getTime() - 604800000);
|
|
|
|
}
|
|
|
|
const year = date.getFullYear()
|
|
|
|
const month = date.getMonth();
|
|
|
|
const day = date.getDate();
|
|
|
|
date.setFullYear(year, month, day);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const minDate = date.getTime();
|
|
|
|
date.setFullYear(year, month, day + 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const maxDate = date.getTime() - 1;
|
|
|
|
dates.push({
|
|
|
|
title: formatWeekLong(minDate),
|
|
|
|
minDate,
|
|
|
|
maxDate
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let matches: any[];
|
|
|
|
if((matches = shortDate.exec(q)) !== null) {
|
|
|
|
const g1 = matches[1];
|
|
|
|
const g2 = matches[3];
|
|
|
|
const k = parseInt(g1);
|
|
|
|
const k1 = parseInt(g2);
|
|
|
|
if(k > 0 && k <= 31) {
|
|
|
|
if(k1 >= minYear && k <= 12) {
|
|
|
|
const selectedYear = k1;
|
|
|
|
const month = k - 1;
|
|
|
|
createForMonthYear(dates, month, selectedYear);
|
|
|
|
return;
|
|
|
|
} else if (k1 <= 12) {
|
|
|
|
const day = k - 1;
|
|
|
|
const month = k1 - 1;
|
|
|
|
createForDayMonth(dates, day, month);
|
|
|
|
}
|
|
|
|
} else if (k >= minYear && k1 <= 12) {
|
|
|
|
const selectedYear = k;
|
|
|
|
const month = k1 - 1;
|
|
|
|
createForMonthYear(dates, month, selectedYear);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((matches = longDate.exec(q)) !== null) {
|
|
|
|
const g1 = matches[1];
|
|
|
|
const g2 = matches[3];
|
|
|
|
const g3 = matches[5];
|
|
|
|
if(!matches[2] === matches[4]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const day = parseInt(g1);
|
|
|
|
const month = parseInt(g2) - 1;
|
|
|
|
let year = parseInt(g3);
|
|
|
|
if(year >= 10 && year <= 99) {
|
|
|
|
year += 2000;
|
|
|
|
}
|
|
|
|
|
|
|
|
const currentYear = new Date().getFullYear();
|
|
|
|
if(validDateForMonth(day - 1, month) && year >= minYear && year <= currentYear) {
|
|
|
|
const date = new Date();
|
|
|
|
date.setFullYear(year, month, day);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const minDate = date.getTime();
|
|
|
|
date.setFullYear(year, month, day + 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const maxDate = date.getTime() - 1;
|
|
|
|
dates.push({
|
|
|
|
title: formatterYearMax(minDate),
|
|
|
|
minDate,
|
|
|
|
maxDate
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((matches = yearPattern.exec(q)) !== null) {
|
|
|
|
let selectedYear = +q;
|
|
|
|
const currentYear = new Date().getFullYear();
|
|
|
|
if(selectedYear < minYear) {
|
|
|
|
selectedYear = minYear;
|
|
|
|
for(let i = currentYear; i >= selectedYear; i--) {
|
|
|
|
const date = new Date();
|
|
|
|
date.setFullYear(i, 0, 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const minDate = date.getTime();
|
|
|
|
date.setFullYear(i + 1, 0, 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const maxDate = date.getTime() - 1;
|
|
|
|
dates.push({
|
|
|
|
title: '' + i,
|
|
|
|
minDate,
|
|
|
|
maxDate
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else if(selectedYear <= currentYear) {
|
|
|
|
const date = new Date();
|
|
|
|
date.setFullYear(selectedYear, 0, 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const minDate = date.getTime();
|
|
|
|
date.setFullYear(selectedYear + 1, 0, 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const maxDate = date.getTime() - 1;
|
|
|
|
dates.push({
|
|
|
|
title: '' + selectedYear,
|
|
|
|
minDate,
|
|
|
|
maxDate
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((matches = monthYearOrDayPattern.exec(q)) !== null) {
|
|
|
|
const g1 = matches[1];
|
|
|
|
const g2 = matches[2];
|
|
|
|
const month = getMonth(g1);
|
|
|
|
if(month >= 0) {
|
|
|
|
const k = +g2;
|
|
|
|
if(k > 0 && k <= 31) {
|
|
|
|
const day = k - 1;
|
|
|
|
createForDayMonth(dates, day, month);
|
|
|
|
return;
|
|
|
|
} else if(k >= minYear) {
|
|
|
|
const selectedYear = k;
|
|
|
|
createForMonthYear(dates, month, selectedYear);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((matches = yearOrDayAndMonthPattern.exec(q)) !== null) {
|
|
|
|
const g1 = matches[1];
|
|
|
|
const g2 = matches[2];
|
|
|
|
const month = getMonth(g2);
|
|
|
|
if(month >= 0) {
|
|
|
|
const k = +g1;
|
|
|
|
if(k > 0 && k <= 31) {
|
|
|
|
const day = k - 1;
|
|
|
|
createForDayMonth(dates, day, month);
|
|
|
|
return;
|
|
|
|
} else if (k >= minYear) {
|
|
|
|
const selectedYear = k;
|
|
|
|
createForMonthYear(dates, month, selectedYear);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function createForMonthYear(dates: DateData[], month: number, selectedYear: number) {
|
|
|
|
const currentYear = new Date().getFullYear();
|
|
|
|
const today = Date.now();
|
|
|
|
if(selectedYear >= minYear && selectedYear <= currentYear) {
|
|
|
|
const date = new Date();
|
|
|
|
date.setFullYear(selectedYear, month, 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
const minDate = date.getTime();
|
|
|
|
if(minDate > today) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
date.setMonth(date.getMonth() + 1);
|
|
|
|
const maxDate = date.getTime() - 1;
|
|
|
|
|
|
|
|
dates.push({
|
|
|
|
title: formatterMonthYear(minDate),
|
|
|
|
minDate,
|
|
|
|
maxDate
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function createForDayMonth(dates: DateData[], day: number, month: number) {
|
|
|
|
if(validDateForMonth(day, month)) {
|
|
|
|
const currentYear = new Date().getFullYear();
|
|
|
|
const today = Date.now();
|
|
|
|
|
|
|
|
for(let i = currentYear; i >= minYear; i--) {
|
|
|
|
if(month === 1 && day === 28 && !isLeapYear(i)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const date = new Date();
|
|
|
|
date.setFullYear(i, month, day + 1);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
|
|
|
|
const minDate = date.getTime();
|
|
|
|
if(minDate > today) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
date.setFullYear(i, month, day + 2);
|
|
|
|
date.setHours(0, 0, 0);
|
|
|
|
const maxDate = date.getTime() - 1;
|
|
|
|
if(i === currentYear) {
|
|
|
|
dates.push({
|
|
|
|
title: formatterDayMonth(minDate),
|
|
|
|
minDate,
|
|
|
|
maxDate
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
dates.push({
|
|
|
|
title: formatterYearMax(minDate),
|
|
|
|
minDate,
|
|
|
|
maxDate
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function formatterMonthYear(timestamp: number) {
|
|
|
|
const date = new Date(timestamp);
|
|
|
|
return months[date.getMonth()].slice(0, 3) + ' ' + date.getFullYear();
|
|
|
|
}
|
|
|
|
|
|
|
|
function formatterDayMonth(timestamp: number) {
|
|
|
|
const date = new Date(timestamp);
|
|
|
|
return months[date.getMonth()].slice(0, 3) + ' ' + date.getDate();
|
|
|
|
}
|
|
|
|
|
|
|
|
function formatterYearMax(timestamp: number) {
|
|
|
|
const date = new Date(timestamp);
|
|
|
|
return ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear();
|
|
|
|
}
|
|
|
|
|
|
|
|
function formatWeekLong(timestamp: number) {
|
|
|
|
const date = new Date(timestamp);
|
|
|
|
return days[date.getDay()];
|
|
|
|
}
|
|
|
|
|
|
|
|
function validDateForMonth(day: number, month: number) {
|
|
|
|
if(month >= 0 && month < 12) {
|
|
|
|
if(day >= 0 && day < numberOfDaysEachMonth[month]) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isLeapYear(year: number) {
|
|
|
|
return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getMonth(q: string) {
|
|
|
|
/* String[] months = new String[]{
|
|
|
|
LocaleController.getString("January", R.string.January).toLowerCase(),
|
|
|
|
LocaleController.getString("February", R.string.February).toLowerCase(),
|
|
|
|
LocaleController.getString("March", R.string.March).toLowerCase(),
|
|
|
|
LocaleController.getString("April", R.string.April).toLowerCase(),
|
|
|
|
LocaleController.getString("May", R.string.May).toLowerCase(),
|
|
|
|
LocaleController.getString("June", R.string.June).toLowerCase(),
|
|
|
|
LocaleController.getString("July", R.string.July).toLowerCase(),
|
|
|
|
LocaleController.getString("August", R.string.August).toLowerCase(),
|
|
|
|
LocaleController.getString("September", R.string.September).toLowerCase(),
|
|
|
|
LocaleController.getString("October", R.string.October).toLowerCase(),
|
|
|
|
LocaleController.getString("November", R.string.November).toLowerCase(),
|
|
|
|
LocaleController.getString("December", R.string.December).toLowerCase()
|
|
|
|
}; */
|
|
|
|
|
|
|
|
/* String[] monthsEng = new String[12];
|
|
|
|
Calendar c = Calendar.getInstance();
|
|
|
|
for (int i = 1; i <= 12; i++) {
|
|
|
|
c.set(0, 0, 0, 0, 0, 0);
|
|
|
|
c.set(Calendar.MONTH, i);
|
|
|
|
monthsEng[i - 1] = c.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.ENGLISH).toLowerCase();
|
|
|
|
} */
|
|
|
|
|
|
|
|
q = q.toLowerCase();
|
|
|
|
for(let i = 0; i < 12; i++) {
|
|
|
|
const month = months[i].toLowerCase();
|
|
|
|
if(month.indexOf(q) === 0) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getDayOfWeek(q: string) {
|
|
|
|
const c = new Date();
|
|
|
|
if(q.length <= 3) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(let i = 0; i < 7; i++) {
|
|
|
|
c.setDate(c.getDate() + 1);
|
|
|
|
|
|
|
|
if(formatWeekLong(c.getTime()).toLowerCase().indexOf(q) === 0) {
|
|
|
|
return c.getDay();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOUNT_CLASS_TO.fillTipDates = fillTipDates;
|