Files
FHC-Core/public/js/composables/CalendarDate.js
T
2025-02-14 14:53:19 +01:00

275 lines
9.2 KiB
JavaScript

import {user_locale} from "../plugin/Phrasen.js";
import CalendarDates from "./CalendarDates.js";
const monthDayRanges = []
for(let i = 1; i < 13; i++) {
monthDayRanges.push(new Date(new Date(Date.now()).getFullYear(), i, 0).getDate())
}
class CalendarDate {
constructor(y, m, d) {
this.weekStart = CalendarDate.getWeekStart();
this.watchLocale = Vue.watch(
user_locale,
(newLocale, oldLocale, onCleanup) =>{
this.weekStart = CalendarDate.getWeekStart();
this._clean();
onCleanup((cleanup)=>{
// do clean up
});
},
);
this.set(y, m, d);
this._clean();
CalendarDates.subscribe(this);
}
get y() { return this._y }
set y(v) { this._y = v; this._clean() }
get m() { return this._m }
set m(v) { this._m = v; this._clean() }
get d() { return this._d }
set d(v) { this._d = v; this._clean() }
/**
* @see https://www.smart-rechner.de/kalenderwochen/rechner.php
*/
get w() {
if (this._w === null) {
if (this.weekStart == 1 && this._m == 11 && this._d > 28 && this.wd <= this._d-29) {
this._w = 1;
} else if (this.weekStart == 1 && this._m == 0 && this._d < 4 && 3-this.wd <= -this._d) {
let weekStartOfTheYear = new Date(this.y-1, 0, this.weekStart == 1 ? 4 : 1);
weekStartOfTheYear.setDate(weekStartOfTheYear.getDate() - (weekStartOfTheYear.getDay() + 7 - this.weekStart)%7);
this._w = Math.ceil((Math.floor((new Date(this.y, this.m, this.d) - weekStartOfTheYear) / 86400000) + 1) / 7);
} else {
let weekStartOfTheYear = new Date(this.y, 0, this.weekStart == 1 ? 4 : 1);
weekStartOfTheYear.setDate(weekStartOfTheYear.getDate() - (weekStartOfTheYear.getDay() + 7 - this.weekStart)%7);
this._w = Math.ceil((Math.floor((new Date(this.y, this.m, this.d) - weekStartOfTheYear) / 86400000) + 1) / 7);
}
}
return this._w;
}
set w(v) {
if (this.w != v) {
let lw = this.numWeeks;
this.d += (v - this.w) * 7;
if (v > 0 && v <= lw && this.w != v) {
if (this.weekStart != 1) {
if (this.w == 1) {
this.set(this.firstDayOfWeek);
} else {
this.set(this.lastDayOfWeek);
}
}
if (this.w != v) {
console.error('couldn\'t set the week', this, v);
}
}
}
}
get wYear() {
if( this.w === 1 ) {
return this.cdLastDayOfWeek.y;
}
return this.cdFirstDayOfWeek.y;
}
get wd() {
if (this._wd === null) {
// the .getDay() method from js Date object ALWAYS returns values from 0 to 6, where 0 is Sunday and 6 is Saturday
// aligns the getDay() result of the Date to the weekStart of the CalendarDate
this._wd = ((new Date(this.y, this.m, this.d)).getDay()+7-this.weekStart)%7;
}
return this._wd;
}
get firstDayOfWeek() {
let firstDayOfWeek = new Date(this.y, this.m, this.d);
// to ensure that firstDayOfWeek.getDay() is always greater than this.weekStart we add 7 and wrap the result around with %7 to avoid negative numbers
firstDayOfWeek.setDate(this.d -(firstDayOfWeek.getDay()+7-this.weekStart)%7);
return firstDayOfWeek;
}
get cdFirstDayOfWeek() {
let FirstDayOfWeek = new CalendarDate(this.firstDayOfWeek);
return FirstDayOfWeek;
}
get lastDayOfWeek() {
let lastDayOfWeek = new Date(this.y, this.m, this.d);
// uses the calculation from firstDayOfWeek and adds 6 days to the result to get the last day of the week
lastDayOfWeek.setDate(this.d -(lastDayOfWeek.getDay()+7-this.weekStart)%7 +6);
return lastDayOfWeek;
}
get wholeWorkWeek() {
const days = []
const date = new Date(this.y, this.m, this.d);
for(let i = 0; i < 5; i++) {
days[i] = new Date(this.y, this.m, this.d)
days[i].setDate(this.d -(date.getDay()+7-this.weekStart)%7 + i)
}
return days
}
get cdLastDayOfWeek() {
let LastDayOfWeek = new CalendarDate(this.lastDayOfWeek);
return LastDayOfWeek;
}
get firstDayOfCalendarMonth() {
let firstDayOfMonth = new Date(this.y, this.m, 1);
let offset = (firstDayOfMonth.getDay() + 7 - this.weekStart) % 7;
// offset will be greater than 1 most of the time, using a negative number for a date returns a date in the past
return new Date(this.y, this.m, 1-offset);
}
get cdFirstDayOfCalendarMonth() {
let firstDayOfMonth = new Date(this.y, this.m, 1);
let offset = (firstDayOfMonth.getDay() + 7 - this.weekStart) % 7;
let FirstDayOfCalendarMonth = new CalendarDate(this.y, this.m, 1 - offset);
return FirstDayOfCalendarMonth;
}
get lastDayOfCalendarMonth() {
// In JavaScript, the Date constructor interprets: A day of 0 as the last day of the previous month
let lastDayOfMonth = new Date(this.y, this.m+1, 0);
let offset = (lastDayOfMonth.getDay() + 7 - this.weekStart) % 7;
return new Date(lastDayOfMonth.getFullYear(), lastDayOfMonth.getMonth(), lastDayOfMonth.getDate()+6-offset);
}
get cdLastDayOfCalendarMonth() {
let lastDayOfMonth = new Date(this.y, this.m+1, 0);
let offset = (lastDayOfMonth.getDay() + 7 - this.weekStart) % 7;
let LasyDayOfCalendarMonth = new CalendarDate(lastDayOfMonth.getFullYear(), lastDayOfMonth.getMonth(), lastDayOfMonth.getDate() + 6 - offset);
return LasyDayOfCalendarMonth;
}
get cdLastDayOfNextCalendarMonth() {
let lastDayOfMonth = new Date(this.y, this.m+1, 0);
let offset = (lastDayOfMonth.getDay() + 7 - this.weekStart) % 7;
let LastDayOfNextCalendarMonth = new CalendarDate(lastDayOfMonth.getFullYear(), lastDayOfMonth.getMonth() + 1, lastDayOfMonth.getDate() + 6 - offset);
return LastDayOfNextCalendarMonth;
}
get nextSevenDays() {
const days = []
for(let i = 0; i < 7; i++) {
days[i] = new Date(this.y, this.m, this.d + i)
}
return days
}
get numWeeks() {
// if the week starts with Monday we have to go 3 days in the past from the start of the next year to get the correct numWeek of the current year
// this is because for example 30.12.2024 - 05.01.2025 is the first calendarWeek of 2025
let lastCalendarWeek = new CalendarDate(this.y + 1, 0, this.weekStart == 1 ? -3 : 0);
return lastCalendarWeek.w;
}
set(y,m,d,noClean) {
if (y !== undefined && (m === undefined || m === true) && d === undefined) {
if (this.isDate(y))
{
// set year/month/day from date object
return this.set(y.getFullYear(), y.getMonth(), y.getDate(), m);
}
if (y.y !== undefined && y.m !== undefined && y.d !== undefined)
{
// set year/month/day from CalendarDate object
return this.set(y.y, y.m, y.d, m);
}
}
// initialize year/month/day
this._y = y ?? 0;
this._m = m ?? 0;
this._d = d ?? 0;
if (!noClean)
this._clean();
}
_clean() {
this.set(new Date(this._y, this._m, this._d), true);
this._w = null;
this._wd = null;
}
format(options, lang=undefined) {
return (new Date(this._y, this._m, this._d)).toLocaleString(lang, options);
}
compare(d) {
if (this.isDate(d))
return (this.y === d.getFullYear() && this.m === d.getMonth() && this.d === d.getDate());
return (this.y === d.y && this.m === d.m && this.d === d.d);
}
isInWeek(w, y) {
if (this.y == y && this.w == w)
return true;
if (this.weekStart == 1)
return false;
let edgeDay = this.cdFirstDayOfWeek;console.log(edgeDay);
if (edgeDay.y == y && edgeDay.w == w)
return true;
edgeDay = this.cdLastDayOfWeek;
if (edgeDay.y == y && edgeDay.w == w)
return true;
return false;
}
setLocale(locale) {
this.weekStart = CalendarDate.getWeekStart(locale);
}
// method that checks if the parameter is of type Date
isDate(obj){
return Object.prototype.toString.call(obj) === '[object Date]';
}
cleanup(){
if(this.watchLocale && this.watchLocale.stop) this.watchLocale.stop(); // TODO: ?
}
moveMonthInDirection (dir) {
// avoid setting date in wrong month if we try to create a date which does not exist like 30th of february
const newM = this.m + dir
const maxDaysTarget = monthDayRanges[newM]
if (this.d > maxDaysTarget) this.d = maxDaysTarget
this.m = newM // calls _clean which sets a new Date
}
}
/**
* Returns the weekday number (Date.getDay()) on which the week starts depending on the locale.
* This can be Saturday(6), Sunday(0) or Monday(1)
*
* @see https://stackoverflow.com/questions/53382465/how-can-i-determine-if-week-starts-on-monday-or-sunday-based-on-locale-in-pure-j
*
* @param string locale
*
* @return integer
*/
CalendarDate.getWeekStart = function(locale) {
locale = user_locale.value || locale || navigator.language;
const parts = locale.match(/^([a-z]{2,3})(?:-([a-z]{3})(?=$|-))?(?:-([a-z]{4})(?=$|-))?(?:-([a-z]{2}|\d{3})(?=$|-))?/i);
const language_code = parts[1];
const language_starting_Sat = ['ar','arq','arz','fa'];
const language_starting_Sun = 'amasbndzengnguhehiidjajvkmknkolomhmlmrmtmyneomorpapssdsmsnsutatethtnurzhzu'.match(/../g);
const region_code = parts[4];
const region_starting_Sat = 'AEAFBHDJDZEGIQIRJOKWLYOMQASDSY'.match(/../g);
const region_starting_Sun = 'AGARASAUBDBRBSBTBWBZCACNCODMDOETGTGUHKHNIDILINJMJPKEKHKRLAMHMMMOMTMXMZNINPPAPEPHPKPRPTPYSASGSVTHTTTWUMUSVEVIWSYEZAZW'.match(/../g);
if (region_code){
if (region_starting_Sun.includes(region_code))
return 0;
else if (region_starting_Sat.includes(region_code))
return 6;
else
return 1;
}
else if(language_code)
{
if (language_starting_Sun.includes(language_code))
return 0;
else if (language_starting_Sat.includes(language_code))
return 6;
else
return 1;
}
else
{
return 1;
}
}
export default CalendarDate