@@ -27,140 +27,239 @@ export default class AmazighCalendarSystem extends CalendarSystemBase {
27
27
) ;
28
28
}
29
29
30
+ // Returns a zero-based month index
30
31
/**
31
32
* Converts a Julian Day Number to an Amazigh date.
32
33
* @param {number } jdn - The Julian Day Number.
33
34
* @returns {Object } An object containing the Amazigh year, month, and day.
34
35
*/
35
- convertFromJulian ( jdn ) {
36
- // Constants for JDN of the Julian calendar start and the Amazigh calendar start year
37
- const JDN_JULIAN_START = 2299160.5 ; // October 15, 1582, Gregorian calendar start (end of Julian calendar)
38
- const AMZ_YEAR_START = 950 ; // Amazigh calendar start year in BC
39
- const DAYS_IN_YEAR = 365.25 ; // Average days in a year accounting for leap years in Julian calendar
40
- const GREGORIAN_START_YEAR = 1582 ; // Year the Gregorian calendar starts
41
- const YENNAYER_JDN_OFFSET = 13 ; // Offset for Yennayer in the Gregorian calendar as of the 21st century
42
-
43
- // Calculate the Gregorian year for the given JDN
44
- let year = GREGORIAN_START_YEAR + Math . floor ( ( jdn - JDN_JULIAN_START ) / DAYS_IN_YEAR ) ;
45
- // Adjust the year based on the Amazigh calendar start year
46
- let amazighYear = year + ( AMZ_YEAR_START - ( year < 0 ? 1 : 0 ) ) ; // Adjust for no year 0 in historical counting
47
-
48
- // Calculate the JDN for January 1st of the given year
49
- let jdnJan1 = jdn - ( ( jdn - JDN_JULIAN_START ) % DAYS_IN_YEAR ) ;
50
- // Calculate the day of the year from JDN
51
- let dayOfYear = jdn - jdnJan1 + 1 ; // +1 since January 1st is day 1
52
-
53
- // Adjust dayOfYear based on the Yennayer offset
54
- dayOfYear -= YENNAYER_JDN_OFFSET ;
55
-
56
- // Correct the year and dayOfYear if the adjustment crosses into the previous year
57
- if ( dayOfYear <= 0 ) {
58
- amazighYear -= 1 ;
59
- dayOfYear += DAYS_IN_YEAR ; // Add the days in a year to the negative dayOfYear
60
- }
36
+ convertFromJulian ( julianDayNumber ) {
37
+ // The Julian Day starts at noon, not at midnight.
38
+ julianDayNumber = julianDayNumber + 0.5 ;
39
+ const [ gy , gm , gd ] = CalendarUtils . jd_to_gregorian ( julianDayNumber ) ;
40
+ const amazighDate = this . adjustForYennayer ( {
41
+ year : gy ,
42
+ month : gm - 1 , // -1 because the jd_to_gregorian returns 1-based months but we need 0-based months for adjustForYennayer
43
+ day : gd ,
44
+ } ) ;
45
+ return new Array ( amazighDate . year , amazighDate . month , amazighDate . day ) ;
46
+ }
61
47
62
- // Determine the month and day from dayOfYear
63
- let month = 0 , day = dayOfYear ;
64
- const daysInMonths = [ 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ] ; // Days in each month for Julian calendar
65
- while ( day > daysInMonths [ month ] ) {
66
- day -= daysInMonths [ month ] ;
67
- month += 1 ;
68
- }
48
+ // Expects a zero-based month index
49
+ // The Julian Day starts at noon, not at midnight.
50
+ // So, when you convert a Gregorian date to a Julian Day number,
51
+ // the result is the Julian Day number for the noon of that day.
52
+ // If the time of the date is noon or later, the Julian Day number will be for the next day.
53
+ convertToJulian (
54
+ calendarYear ,
55
+ calendarMonth ,
56
+ calendarDay ,
57
+ hour = 0 ,
58
+ minute = 0 ,
59
+ second = 0
60
+ ) {
61
+ // Convert Amazigh year to Gregorian year
62
+ const gregorianYear = calendarYear - 950 ; // Amazigh calendar starts in 950 BC in the Gregorian calendar
69
63
70
- // Adjust for the Amazigh calendar specifics if necessary
71
- // Note: This example uses a simplified approach and might need adjustments for leap years and accurate month lengths
64
+ // Initial conversion without adjusting for Yennayer
65
+ let gregorianDate = {
66
+ year : gregorianYear ,
67
+ month : calendarMonth ,
68
+ day : calendarDay ,
69
+ } ;
72
70
73
- return [
74
- amazighYear ,
75
- month + 1 , // +1 to make the month 1-based
76
- day
77
- ] ;
78
- }
71
+ const yennayerGregorianDate = new Date ( gregorianYear , 0 , 14 ) ; // January is month 0 in JavaScript Date
79
72
73
+ // Calculate the Julian Day Number (JDN) for Yennayer
74
+ let julianDayYennayer = CalendarUtils . gregorian_to_jd (
75
+ yennayerGregorianDate . getFullYear ( ) ,
76
+ yennayerGregorianDate . getMonth ( ) + 1 ,
77
+ yennayerGregorianDate . getDate ( )
78
+ ) ;
80
79
81
- // Convert Amazigh date to Julian Day
82
- convertToJulian ( calendarYear , calendarMonth , calendarDay ) {
83
- // Convert Amazigh year to Gregorian year
84
- const gregorianYear = calendarYear + 950 ;
85
- // Adjusting for Yennayer starting on January 14th in the Gregorian calendar
86
- const isBeforeYennayer = calendarMonth === 0 && calendarDay < 14 ;
87
- const adjustedYear = gregorianYear - ( isBeforeYennayer ? 1 : 0 ) ;
88
- const adjustedMonth = isBeforeYennayer ? 12 : calendarMonth + 1 ; // Adjust month to 1-based for calculation
89
- const adjustedDay = calendarDay + ( isBeforeYennayer ? 18 : 13 ) ; // Adjust days for Yennayer start, considering the current 13-day discrepancy
90
-
91
- // Convert adjusted Gregorian date to Julian Day
92
- return CalendarUtils . gregorian_to_jd ( adjustedYear , adjustedMonth , adjustedDay ) ;
93
- }
80
+ // Step 3: Calculate the total number of days from Yennayer to the given Amazigh date
81
+ // Adjust month and day based on dayOfYear
82
+ const daysInMonths = [
83
+ 31 ,
84
+ calendarYear % 4 === 0 ? 29 : 28 ,
85
+ 31 ,
86
+ 30 ,
87
+ 31 ,
88
+ 30 ,
89
+ 31 ,
90
+ 31 ,
91
+ 30 ,
92
+ 31 ,
93
+ 30 ,
94
+ 31 ,
95
+ ] ; // Considering leap years
96
+ let daysSinceYennayer = 0 ;
97
+ for ( let month = 0 ; month < calendarMonth ; month ++ ) {
98
+ // Assuming 30 days per month for simplicity; adjust based on the actual Amazigh calendar if necessary
99
+ daysSinceYennayer += daysInMonths [ month ] ;
100
+ }
94
101
102
+ daysSinceYennayer += calendarDay - 1 ; // Subtract 1 since Yennayer is day 1
103
+
104
+ // Calculate the final Julian Day Number (JDN) by adding the days since Yennayer to the JDN of Yennayer
105
+ let finalJdn = julianDayYennayer + daysSinceYennayer
106
+ // Adjust for the time of day
107
+ + Math . floor ( second + 60 * ( minute + 60 * hour ) + 0.5 ) / 86400.0
108
+
109
+ return finalJdn ;
110
+ }
95
111
96
112
// Convert from Gregorian date to Amazigh date
113
+ // Returns a zero-based month index
114
+ // Expects a zero-based month index
97
115
convertFromGregorian ( date ) {
98
- const julianDay = CalendarUtils . gregorian_to_jd ( date . getFullYear ( ) , date . getMonth ( ) + 1 , date . getDate ( ) ) ;
99
- const gregorianYear = date . getFullYear ( ) ;
100
- const gregorianMonth = date . getMonth ( ) + 1 ; // 1-based month
101
- const gregorianDay = date . getDate ( ) ;
102
-
103
- // Calculate the Amazigh year
104
- let amazighYear = gregorianYear - 950 ;
105
- if ( gregorianMonth < 1 || ( gregorianMonth === 1 && gregorianDay < 14 ) ) {
106
- amazighYear -= 1 ; // Adjust for Yennayer
107
- }
108
-
109
- // Convert Julian day back to Gregorian to adjust for Yennayer offset
110
- const { year, month, day } = CalendarUtils . jd_to_gregorian ( julianDay - 13 ) ;
116
+ date = this . validateDate ( date ) ;
111
117
118
+ const julianDay =
119
+ CalendarUtils . gregorian_to_jd (
120
+ date . getFullYear ( ) ,
121
+ date . getMonth ( ) + 1 ,
122
+ date . getDate ( )
123
+ ) +
124
+ Math . floor (
125
+ date . getSeconds ( ) +
126
+ 60 * ( date . getMinutes ( ) + 60 * date . getHours ( ) ) +
127
+ 0.5
128
+ ) /
129
+ 86400.0 -
130
+ 0.5 ;
131
+ const convertedDateArray = this . convertFromJulian ( julianDay ) ;
112
132
return {
113
- year : year - 950 ,
114
- month : month - 1 , // Convert to 0-based month index
115
- day : day ,
133
+ year : convertedDateArray [ 0 ] ,
134
+ month : convertedDateArray [ 1 ] - 1 , // -1 because the month is 0-based
135
+ day : convertedDateArray [ 2 ] ,
116
136
} ;
117
137
}
118
138
119
- convertToGregorian ( calendarYear , calendarMonth , calendarDay ) {
120
- // Calculate the Gregorian year for the given Amazigh year.
121
- const baseYear = - 950 ; // Starting point of the Amazigh calendar in the Gregorian calendar (950 BC).
122
- let gregorianYear = calendarYear + baseYear ;
123
-
124
- // Adjust for the current discrepancy between the Julian and Gregorian calendars.
125
- const discrepancyDays = 13 ; // As of the 21st century, there's a 13-day difference between the calendars.
126
- const yennayerGregorianDate = new Date ( gregorianYear , 0 , 14 + discrepancyDays ) ; // January 14th + discrepancy in days.
127
-
128
- // Calculate the Julian Day Number for Yennayer of the given Gregorian year.
129
- let julianDayYennayer = this . convertToJulian ( yennayerGregorianDate . getFullYear ( ) , yennayerGregorianDate . getMonth ( ) , yennayerGregorianDate . getDate ( ) ) ;
130
-
131
- // Considering the Amazigh calendar follows the Julian calendar with months having the same length,
132
- // we calculate the total number of days since Yennayer to the Amazigh date.
133
- let daysSinceYennayer = 0 ;
134
- for ( let month = 0 ; month < calendarMonth ; month ++ ) {
135
- daysSinceYennayer += month === 1 ? 28 : ( month < 7 ? ( month % 2 === 0 ? 31 : 30 ) : ( month % 2 === 0 ? 30 : 31 ) ) ;
136
- }
137
- daysSinceYennayer += calendarDay - 1 ; // Subtract one since Yennayer is considered day 1.
138
-
139
- // Calculate the total Julian Day and convert it back to a Gregorian date.
140
- let julianDay = julianDayYennayer + daysSinceYennayer ;
139
+ // Returns a zero-based month index
140
+ // Expects a zero-based month index
141
+ convertToGregorian (
142
+ calendarYear ,
143
+ calendarMonth ,
144
+ calendarDay ,
145
+ hour = 0 ,
146
+ minute = 0 ,
147
+ second = 0 ,
148
+ millisecond = 0
149
+ ) {
150
+ const julianDay = this . convertToJulian (
151
+ calendarYear ,
152
+ calendarMonth ,
153
+ calendarDay ,
154
+ hour ,
155
+ minute ,
156
+ second ,
157
+ millisecond
158
+ ) ;
141
159
const gregorianDateArray = CalendarUtils . jd_to_gregorian ( julianDay ) ;
142
160
return {
143
161
year : gregorianDateArray [ 0 ] ,
144
162
month : gregorianDateArray [ 1 ] - 1 , // -1 because the Gregorian month is 0-based
145
163
day : gregorianDateArray [ 2 ] ,
146
164
} ;
147
- }
165
+ }
148
166
149
- isLeapYear ( year ) {
167
+ isLeapYear ( year = null ) {
168
+ if ( year === null ) {
169
+ year = this . $y ;
170
+ }
150
171
// Adjust if Amazigh leap year rules differ, using Gregorian as placeholder
151
172
const adjustedYear = year + 950 ;
152
- return ( adjustedYear % 4 === 0 && adjustedYear % 100 !== 0 ) || adjustedYear % 400 === 0 ;
173
+ return (
174
+ ( adjustedYear % 4 === 0 && adjustedYear % 100 !== 0 ) ||
175
+ adjustedYear % 400 === 0
176
+ ) ;
153
177
}
154
- monthNames (
155
- locale = "en" ,
156
- calendar = "amazigh" ,
157
- firstMonthName = "Yennayer"
158
- ) {
178
+
179
+ monthNames ( locale = "en" , calendar = "amazigh" , firstMonthName = "Yennayer" ) {
159
180
return generateMonthNames ( locale , calendar , firstMonthName ) ;
160
181
}
161
182
162
183
getLocalizedMonthName ( monthIndex ) {
163
184
return this . monthNamesLocalized [ monthIndex ] ;
164
185
}
165
- }
166
186
187
+ gregorianToAmazighYear ( gregorianYear ) {
188
+ // The Amazigh year 2974 corresponds to Gregorian year 2024
189
+ const referenceAmazighYear = 2974 ;
190
+ const referenceGregorianYear = 2024 ;
191
+ const yearDifference = gregorianYear - referenceGregorianYear ;
192
+ return referenceAmazighYear + yearDifference ;
193
+ }
194
+
195
+ // Returns a zero-based month index
196
+ // Expects a zero-based month index
197
+ adjustForYennayer ( gregorianDate ) {
198
+ // Constants for the Amazigh New Year in the Gregorian calendar
199
+ const yennayerMonth = 0 ; // January, zero-based index
200
+ const yennayerDay = 14 ;
201
+
202
+ // Convert the Gregorian year to the Amazigh year
203
+ let amazighYear = this . gregorianToAmazighYear ( gregorianDate . year ) ;
204
+
205
+ // Check if the Gregorian date is before Yennayer and adjust the Amazigh year accordingly
206
+ if (
207
+ gregorianDate . month < yennayerMonth ||
208
+ ( gregorianDate . month === yennayerMonth && gregorianDate . day < yennayerDay )
209
+ ) {
210
+ amazighYear -= 1 ; // The date is in the previous Amazigh year
211
+ }
212
+
213
+ // Calculate the Julian Day Number for the given Gregorian date and for Yennayer
214
+ const jdnForGregorianDate = CalendarUtils . gregorian_to_jd (
215
+ gregorianDate . year ,
216
+ gregorianDate . month + 1 ,
217
+ gregorianDate . day
218
+ ) ;
219
+ const jdnForYennayerThisYear = CalendarUtils . gregorian_to_jd (
220
+ gregorianDate . year ,
221
+ yennayerMonth + 1 ,
222
+ yennayerDay
223
+ ) ;
224
+
225
+ // Determine if we need to use Yennayer from the previous Gregorian year for the calculation
226
+ const usePreviousYearYennayer =
227
+ gregorianDate . month < yennayerMonth ||
228
+ ( gregorianDate . month === yennayerMonth &&
229
+ gregorianDate . day < yennayerDay ) ;
230
+ const jdnForYennayer = usePreviousYearYennayer
231
+ ? CalendarUtils . gregorian_to_jd (
232
+ gregorianDate . year - 1 ,
233
+ yennayerMonth + 1 ,
234
+ yennayerDay
235
+ )
236
+ : jdnForYennayerThisYear ;
237
+
238
+ // Calculate the day of the year in the Amazigh calendar
239
+ let dayOfYear = jdnForGregorianDate - jdnForYennayer + 1 ; // +1 because Yennayer is day 1
240
+
241
+ // Determine the Amazigh month and day from the day of the year
242
+ const daysInAmazighMonths = [
243
+ 31 ,
244
+ amazighYear % 4 === 0 ? 29 : 28 ,
245
+ 31 ,
246
+ 30 ,
247
+ 31 ,
248
+ 30 ,
249
+ 31 ,
250
+ 31 ,
251
+ 30 ,
252
+ 31 ,
253
+ 30 ,
254
+ 31 ,
255
+ ] ; // Considering leap years
256
+ let month = 0 ;
257
+ while ( dayOfYear > daysInAmazighMonths [ month ] ) {
258
+ dayOfYear -= daysInAmazighMonths [ month ] ;
259
+ month ++ ;
260
+ }
261
+
262
+ // Adjust month to be zero-based and ensure dayOfYear is correctly calculated
263
+ return { year : amazighYear , month : month + 1 , day : dayOfYear } ;
264
+ }
265
+ }
0 commit comments