Skip to content

Commit 731d5c5

Browse files
committed
feat: code optimization, cleanup and more functions. Added a WIP for Ethiopian calendar, still not stable. Fixed timezone and utc calculations
1 parent a6eaecd commit 731d5c5

13 files changed

+554
-281
lines changed

Diff for: .github/dependabot.yml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5+
6+
version: 2
7+
updates:
8+
- package-ecosystem: "yarn" # See documentation for possible values
9+
directory: "/" # Location of package manifests
10+
schedule:
11+
interval: "weekly"

Diff for: dev/__wip__/overwrites.dayjs.function.js

+63-56
Original file line numberDiff line numberDiff line change
@@ -15,63 +15,70 @@ dayjsClass.prototype.tz = function (timezone = defaultTimezone, keepLocalTime) {
1515
return ins
1616
}
1717
18-
dayjsClass.prototype.utcOffset = function (input, keepLocalTime) {
19-
const { u } = this.$utils()
20-
if (u(input)) {
21-
if (this.$u) {
22-
return 0
23-
}
24-
if (!u(this.$offset)) {
25-
return this.$offset
26-
}
27-
return -Math.round(this.$d.getTimezoneOffset() / 15) * 15;
28-
}
18+
// dayjsClass.prototype.OFF_utcOffset = function (input, keepLocalTime) {
19+
// const { u } = this.$utils()
20+
// if (u(input)) {
21+
// if (this.$u) {
22+
// return 0
23+
// }
24+
// if (!u(this.$offset)) {
25+
// return this.$offset
26+
// }
27+
// return -Math.round(this.$d.getTimezoneOffset() / 15) * 15;
28+
// }
2929
30-
if (typeof input === 'string') {
31-
input = offsetFromString(input)
32-
if (input === null) {
33-
return this
34-
}
35-
}
36-
const offset = Math.abs(input) <= 16 ? input * 60 : input
37-
let ins = this.clone();
38-
if (keepLocalTime) {
39-
ins.$offset = offset
40-
ins.$u = input === 0
41-
return ins
42-
}
43-
if (input !== 0) {
44-
const localTimezoneOffset = this.$u
45-
? this.toDate().getTimezoneOffset() : -1 * this.utcOffset()
30+
// if (typeof input === 'string') {
31+
// input = offsetFromString(input)
32+
// if (input === null) {
33+
// return this
34+
// }
35+
// }
36+
// const offset = Math.abs(input) <= 16 ? input * 60 : input
37+
// let ins = this.clone();
38+
// if (keepLocalTime) {
39+
// ins.$offset = offset
40+
// ins.$u = input === 0
41+
// return ins
42+
// }
43+
// if (input !== 0) {
44+
// const localTimezoneOffset = this.$u
45+
// ? this.toDate().getTimezoneOffset() : -1 * this.utcOffset()
4646
47-
ins = this.local().add(offset + localTimezoneOffset, MIN)
48-
ins.$offset = offset
49-
ins.$x.$localOffset = localTimezoneOffset
50-
} else {
51-
ins = this.utc()
52-
}
53-
return ins
54-
}
47+
// ins = this.local().add(offset + localTimezoneOffset, MIN)
48+
// ins.$offset = offset
49+
// ins.$x.$localOffset = localTimezoneOffset
50+
// } else {
51+
// ins = this.utc()
52+
// }
53+
// return ins
54+
// }
5555
56-
dayjsClass.prototype.utc = function (keepLocalTime) {
57-
let y = this.$y;
58-
let m = this.$M;
59-
let d = this.$D;
60-
// if calendar system is not gregorian, convert the date to gregorian
61-
if ("$C" in this && this.$C !== "gregory") {
62-
const convertedDate = calendarSystems[this.$C].convertToGregorian(
63-
this.$y,
64-
this.$M,
65-
this.$D
66-
);
67-
y = convertedDate.year;
68-
m = convertedDate.month;
69-
d = convertedDate.day;
70-
}
71-
const ins = wrapper(Date.UTC(y, m, d), { ...this, locale: this.$L, utc: true, $u: true })
72-
if (keepLocalTime) {
73-
return ins.add(this.utcOffset(), "minute")
74-
}
75-
return ins
76-
}
56+
// dayjsClass.prototype.OFF_utc = function (keepLocalTime) {
57+
// let y = this.$y;
58+
// let m = this.$M;
59+
// let d = this.$D;
60+
// // if calendar system is not gregorian, convert the date to gregorian
61+
// if ("$C" in this && this.$C !== "gregory") {
62+
// const convertedDate = calendarSystems[this.$C].convertToGregorian(
63+
// this.$y,
64+
// this.$M,
65+
// this.$D,
66+
// this.$H,
67+
// this.$m,
68+
// this.$s,
69+
// this.$ms
70+
// );
71+
// y = convertedDate.year;
72+
// m = convertedDate.month;
73+
// d = convertedDate.day;
74+
// }
75+
// //const ins = wrapper(Date.UTC(y, m, d), { ...this, locale: this.$L, utc: true });
76+
// const date = this.format("YYYY-MM-DDTHH:mm:ss.SSS");
77+
// const ins = wrapper(date, { ...this, locale: this.$L, utc: true });
78+
79+
// if (keepLocalTime) {
80+
// return ins.add(this.utcOffset(), "minute")
81+
// }
82+
// return ins
83+
// }
7784
*/

Diff for: src/calendarSystems/CalendarSystemBase.js

+56
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,17 @@ export default class CalendarSystemBase {
3838
);
3939
}
4040

41+
convertFromJulian(date) {
42+
throw new Error("Method convertToJulian must be implemented by subclass");
43+
}
44+
4145
// Expects a zero-based month index
46+
// Retrieve the Julian date equivalent for this date,
47+
// i.e. days since January 1, 4713 BCE Greenwich noon.
48+
// The Julian Day starts at noon, not at midnight.
49+
// So, when you convert a Gregorian date to a Julian Day number,
50+
// the result is the Julian Day number for the noon of that day.
51+
// If the time of the date is noon or later, the Julian Day number will be for the next day.
4252
convertToJulian(date) {
4353
throw new Error("Method convertToJulian must be implemented by subclass");
4454
}
@@ -73,4 +83,50 @@ export default class CalendarSystemBase {
7383
),
7484
};
7585
}
86+
87+
validateDate(date) {
88+
// extract year, month, day from date.
89+
// date can be of type Date, Dayjs or object.
90+
// if date is object, it should have year, month and day properties.
91+
// if date is Dayjs, it should have $y, $M and $D properties.
92+
// if date is Date, it should have getFullYear(), getMonth() and getDate() methods.
93+
// if date is string, it should be in ISO format.
94+
// if date is number, it should be in milliseconds.
95+
// if date is undefined, it should be now.
96+
// if date is null, it should be now.
97+
if (date === undefined || date === null) {
98+
date = new Date();
99+
} else if (typeof date === "string") {
100+
date = new Date(date);
101+
} else if (typeof date === "number") {
102+
date = new Date(date);
103+
} else if (date instanceof Date) {
104+
// do nothing
105+
} else if (
106+
date.$y !== undefined &&
107+
date.$M !== undefined &&
108+
date.$D !== undefined
109+
) {
110+
date = new Date(
111+
date.$y,
112+
date.$M,
113+
date.$D,
114+
date.$H,
115+
date.$m,
116+
date.$s,
117+
date.$ms
118+
);
119+
} else if (
120+
date.year !== undefined &&
121+
date.month !== undefined &&
122+
date.day !== undefined
123+
) {
124+
date = new Date(date.year, date.month, date.day);
125+
} else {
126+
throw new Error("Invalid date");
127+
}
128+
129+
return date;
130+
}
131+
76132
}

Diff for: src/calendarSystems/EthiopianCalendarSystem.js

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/**
2+
* Ethiopian Calendar System
3+
*
4+
* @file EthiopianCalendarSystem.js
5+
* @project dayjs-calendarsystems
6+
* @license see LICENSE file included in the project
7+
* @author Calidy.com, Amir Moradi (https://calidy.com/)
8+
* @description see README.md file included in the project
9+
*
10+
*/
11+
12+
import CalendarSystemBase from "./CalendarSystemBase";
13+
import * as CalendarUtils from "../calendarUtils/fourmilabCalendar";
14+
import { generateMonthNames } from "../calendarUtils/IntlUtils";
15+
16+
export default class EthiopianCalendarSystem extends CalendarSystemBase {
17+
constructor(locale = "en") {
18+
super();
19+
this.firstDayOfWeek = 0; // Sunday
20+
this.locale = locale;
21+
// Julian date of start of Ethiopian epoch: 27 August 8 CE (Gregorian).
22+
this.julianDayEpoch = 1724220.5;
23+
this.intlCalendar = "ethiopic";
24+
this.firstMonthNameEnglish = "Meskerem";
25+
this.monthNamesLocalized = generateMonthNames(
26+
locale,
27+
"ethiopic",
28+
"Meskerem"
29+
);
30+
}
31+
32+
convertFromJulian(julianDayNumber) {
33+
// Calculate the number of days since the Ethiopian epoch
34+
const days = Math.floor(julianDayNumber) + 0.5 - this.julianDayEpoch;
35+
// Calculate the Ethiopian year
36+
const year = Math.floor((days - Math.floor((days + 366) / 1461)) / 365) + 1;
37+
// Calculate the day of the year (1-366)
38+
const dayOfYear = days - (year - 1) * 365 - Math.floor((year - 1) / 4);
39+
// Calculate the Ethiopian month (1-13)
40+
const month = dayOfYear > 330 ? 13 : Math.floor((dayOfYear - 1) / 30) + 1;
41+
// Calculate the day of the month (1-30 for months 1-12, 1-5 or 1-6 for month 13)
42+
const day = Math.floor(dayOfYear - (month - 1) * 30) + 1;
43+
// Return the Ethiopian date
44+
return [year, month, day];
45+
}
46+
47+
// Expects a zero-based month index
48+
// The Julian Day starts at noon, not at midnight.
49+
// So, when you convert a Gregorian date to a Julian Day number,
50+
// the result is the Julian Day number for the noon of that day.
51+
// If the time of the date is noon or later, the Julian Day number will be for the next day.
52+
convertToJulian(
53+
calendarYear,
54+
calendarMonth,
55+
calendarDay,
56+
hour = 0,
57+
minute = 0,
58+
second = 0
59+
) {
60+
// Calculate the Julian Day number for the start of this Ethiopian year
61+
const yearStart =
62+
(calendarYear - 1) * 365 +
63+
Math.floor(calendarYear / 4) +
64+
this.julianDayEpoch;
65+
// Calculate the Julian Day number for the start of this Ethiopian month
66+
const monthStart = yearStart + calendarMonth * 30;
67+
// Calculate the Julian Day number for this Ethiopian day
68+
const dayStart = monthStart + calendarDay - 1;
69+
// Adjust for the time of day
70+
const time = (second + 60 * (minute + 60 * hour)) / 86400.0;
71+
// Return the total Julian Day number
72+
return dayStart + time;
73+
}
74+
75+
convertFromGregorian(date) {
76+
date = this.validateDate(date);
77+
78+
const julianDay =
79+
CalendarUtils.gregorian_to_jd(
80+
date.getFullYear(),
81+
date.getMonth() + 1,
82+
date.getDate()
83+
) +
84+
Math.floor(
85+
date.getSeconds() +
86+
60 * (date.getMinutes() + 60 * date.getHours()) +
87+
0.5
88+
) /
89+
86400.0 -
90+
0.5;
91+
const convertedDateArray = this.convertFromJulian(julianDay);
92+
return {
93+
year: convertedDateArray[0],
94+
month: convertedDateArray[1] - 1, // -1 because the month is 0-based
95+
day: convertedDateArray[2],
96+
};
97+
}
98+
99+
// Returns a zero-based month index
100+
// Expects a zero-based month index
101+
convertToGregorian(
102+
calendarYear,
103+
calendarMonth,
104+
calendarDay,
105+
hour = 0,
106+
minute = 0,
107+
second = 0,
108+
millisecond = 0
109+
) {
110+
const julianDay = this.convertToJulian(
111+
calendarYear,
112+
calendarMonth,
113+
calendarDay,
114+
hour,
115+
minute,
116+
second,
117+
millisecond
118+
);
119+
const gregorianDateArray = CalendarUtils.jd_to_gregorian(julianDay - 0.5);
120+
return {
121+
year: gregorianDateArray[0],
122+
month: gregorianDateArray[1] - 1, // -1 because the Gregorian month is 0-based
123+
day: gregorianDateArray[2],
124+
};
125+
}
126+
127+
isLeapYear() {
128+
this.$y = this.$y + (this.$y < 0 ? 1 : 0); // No year zero
129+
return this.$y % 4 === 3 || this.$y % 4 === -1;
130+
}
131+
132+
monthNames(
133+
locale = "en",
134+
calendar = "ethiopic",
135+
firstMonthName = "Meskerem"
136+
) {
137+
return generateMonthNames(locale, calendar, firstMonthName);
138+
}
139+
getLocalizedMonthName(monthIndex) {
140+
return this.monthNamesLocalized[monthIndex];
141+
}
142+
}

Diff for: src/calendarSystems/GregoryCalendarSystem.js

+2-32
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export default class GregoryCalendarSystem extends CalendarSystemBase {
2222
this.monthNamesLocalized = generateMonthNames(locale, "gregory", "January");
2323
}
2424

25+
// Expects a zero-based month index
2526
convertToJulian(calendarYear, calendarMonth, calendarDay) {
2627
// calendarMonth = calendarMonth+1 because the *_to_jd function month is 1-based
2728
return CalendarUtils.gregorian_to_jd(
@@ -32,38 +33,7 @@ export default class GregoryCalendarSystem extends CalendarSystemBase {
3233
}
3334

3435
convertFromGregorian(date) {
35-
// extract year, month, day from date.
36-
// date can be of type Date, Dayjs or object.
37-
// if date is object, it should have year, month and day properties.
38-
// if date is Dayjs, it should have $y, $M and $D properties.
39-
// if date is Date, it should have getFullYear(), getMonth() and getDate() methods.
40-
// if date is string, it should be in ISO format.
41-
// if date is number, it should be in milliseconds.
42-
// if date is undefined, it should be now.
43-
// if date is null, it should be now.
44-
if (date === undefined || date === null) {
45-
date = new Date();
46-
} else if (typeof date === "string") {
47-
date = new Date(date);
48-
} else if (typeof date === "number") {
49-
date = new Date(date);
50-
} else if (date instanceof Date) {
51-
// do nothing
52-
} else if (
53-
date.$y !== undefined &&
54-
date.$M !== undefined &&
55-
date.$D !== undefined
56-
) {
57-
date = new Date(date.$y, date.$M, date.$D);
58-
} else if (
59-
date.year !== undefined &&
60-
date.month !== undefined &&
61-
date.day !== undefined
62-
) {
63-
date = new Date(date.year, date.month, date.day);
64-
} else {
65-
throw new Error("Invalid date");
66-
}
36+
date = this.validateDate(date);
6737

6838
return date;
6939
}

0 commit comments

Comments
 (0)