HijrahDate — реализация исламского календаря Hijrah в
библиотеке Js-joda. Этот календарь отличается от григорианского не
только набором месяцев и летоисчислением, но и самой логикой вычисления
дат. Основан на лунных циклах, поэтому длина месяцев и годов отличается
от привычного календаря ISO.
Класс HijrahDate входит в модуль хронологий
(chrono) и предоставляет полноценную работу с исламскими
датами: создание объектов, арифметику дат, преобразования,
форматирование и межкалендарные операции.
Поддержка альтернативных календарей находится в отдельном пакете:
npm install @js-joda/core
npm install @js-joda/locale
npm install @js-joda/extra
Импорт:
import {
HijrahChronology,
HijrahDate,
ChronoField,
ChronoUnit
} from '@js-joda/core'
Hijrah-календарь обладает рядом особенностей:
| Особенность | Описание |
|---|---|
| Лунный календарь | Основан на фазах Луны |
| 12 месяцев | Как и в ISO-календаре |
| Год короче | Обычно 354 или 355 дней |
| Смещение относительно ISO | Годы не совпадают |
| Названия месяцев | Muharram, Safar, Ramadan и др. |
const date = HijrahDate.now()
console.log(date.toString())
Пример результата:
Hijrah-umalqura AH 1447-09-12
const chronology = HijrahChronology.INSTANCE
const date = chronology.date(1445, 9, 1)
console.log(date.toString())
const date = HijrahDate.of(1445, 10, 15)
console.log(date.toString())
Hijrah-дата состоит из:
year)month)dayOfMonth)era)Пример:
const date = HijrahDate.of(1445, 9, 20)
console.log(date.year())
console.log(date.monthValue())
console.log(date.dayOfMonth())
const date = HijrahDate.of(1445, 9, 10)
console.log(date.get(ChronoField.YEAR))
console.log(date.get(ChronoField.MONTH_OF_YEAR))
console.log(date.get(ChronoField.DAY_OF_MONTH))
console.log(
date.get(ChronoField.DAY_OF_YEAR)
)
console.log(
date.get(ChronoField.DAY_OF_WEEK)
)
Значения:
| День | Значение |
|---|---|
| Monday | 1 |
| Tuesday | 2 |
| Wednesday | 3 |
| Thursday | 4 |
| Friday | 5 |
| Saturday | 6 |
| Sunday | 7 |
import { LocalDate } from '@js-joda/core'
const isoDate = LocalDate.of(2025, 3, 10)
const hijrahDate =
HijrahChronology.INSTANCE.date(isoDate)
console.log(hijrahDate.toString())
const isoDate = LocalDate.from(hijrahDate)
console.log(isoDate.toString())
const date = HijrahDate.of(1445, 9, 1)
const next = date.plusDays(10)
console.log(next.toString())
const prev = date.minusDays(5)
console.log(prev.toString())
const result = date.plusMonths(2)
console.log(result.toString())
const result = date.plusYears(1)
console.log(result.toString())
const date = HijrahDate.of(1445, 9, 10)
console.log(
date.plus(2, ChronoUnit.MONTHS)
)
console.log(
date.minus(15, ChronoUnit.DAYS)
)
const updated = date.withYear(1450)
console.log(updated.toString())
const updated = date.withMonth(12)
console.log(updated.toString())
const updated = date.withDayOfMonth(1)
console.log(updated.toString())
Исламский календарь использует эру AH (Anno
Hegirae).
console.log(date.era())
Поскольку календарь лунный, длина месяцев различается.
console.log(date.lengthOfMonth())
Результат:
29
или
30
console.log(date.lengthOfYear())
Возможные значения:
354
355
console.log(date.isLeapYear())
const d1 = HijrahDate.of(1445, 9, 1)
const d2 = HijrahDate.of(1445, 9, 1)
console.log(d1.equals(d2))
console.log(d1.isBefore(d2))
console.log(d1.isAfter(d2))
console.log(
d1.compareTo(d2)
)
Все хронологии в Js-joda могут быть представлены через epoch day.
console.log(date.toEpochDay())
Это позволяет сравнивать даты разных календарей.
const iso = LocalDate.of(2025, 1, 1)
const hijrah =
HijrahChronology.INSTANCE.date(iso)
console.log(hijrah.toEpochDay())
console.log(iso.toEpochDay())
Значения будут одинаковыми.
HijrahDate поддерживает интерфейсы temporal API.
console.log(
date.isSupported(ChronoField.YEAR)
)
console.log(
date.isSupported(ChronoUnit.MONTHS)
)
console.log(date.toString())
Пример:
Hijrah-umalqura AH 1445-09-10
import {
DateTimeFormatter
} from '@js-joda/core'
const formatter =
DateTimeFormatter.ofPattern(
'yyyy-MM-dd'
)
console.log(
formatter.format(date)
)
const formatter =
DateTimeFormatter
.ofPattern('dd MMM yyyy')
.withChronology(
HijrahChronology.INSTANCE
)
console.log(formatter.format(date))
const formatter =
DateTimeFormatter.ofPattern(
'yyyy-MM-dd'
)
const parsed =
HijrahDate.from(
formatter.parse('1445-09-15')
)
console.log(parsed.toString())
const first =
date.withDayOfMonth(1)
console.log(first.toString())
const last =
date.withDayOfMonth(
date.lengthOfMonth()
)
console.log(last.toString())
console.log(
date.range(
ChronoField.DAY_OF_MONTH
)
)
console.log(
date.chronology()
)
console.log(
date.chronology().id()
)
console.log(
date.chronology().calendarType()
)
const start =
HijrahDate.of(1445, 1, 1)
const end =
HijrahDate.of(1445, 10, 1)
const period =
start.until(end)
console.log(period.toString())
const days =
ChronoUnit.DAYS.between(
start,
end
)
console.log(days)
const months =
ChronoUnit.MONTHS.between(
start,
end
)
console.log(months)
Все объекты HijrahDate неизменяемы.
const original =
HijrahDate.of(1445, 9, 1)
const changed =
original.plusDays(5)
console.log(original.toString())
console.log(changed.toString())
Исходный объект не изменяется.
HijrahDate.of(1445, 15, 10)
Ошибка:
DateTimeException
HijrahDate.of(1445, 9, 35)
| Операция | Поддержка |
|---|---|
| plusDays | Да |
| plusMonths | Да |
| plusYears | Да |
| minusDays | Да |
| compareTo | Да |
| until | Да |
| format | Да |
| parse | Да |
const date = HijrahDate.now()
if (date.monthValue() === 9) {
console.log('Ramadan')
}
function endOfMonth(date) {
return date.withDayOfMonth(
date.lengthOfMonth()
)
}
const result =
endOfMonth(
HijrahDate.of(1445, 9, 1)
)
console.log(result.toString())
import {
LocalDate,
HijrahChronology
} from '@js-joda/core'
const iso =
LocalDate.of(2026, 1, 15)
const hijrah =
HijrahChronology
.INSTANCE
.date(iso)
console.log(iso.toString())
console.log(hijrah.toString())
const dates = [
HijrahDate.of(1445, 9, 10),
HijrahDate.of(1445, 1, 5),
HijrahDate.of(1445, 12, 1)
]
dates.sort((a, b) =>
a.compareTo(b)
)
console.log(dates)
Нельзя жёстко рассчитывать количество дней в месяце.
Неправильно:
date.plusDays(30)
Правильно:
date.plusMonths(1)
Между календарями отсутствует прямое соответствие месяцев и годов.
В мире существует несколько вариантов Hijrah-календарей:
Js-joda использует реализацию Hijrah-umalqura.
Предпочтительно:
date.plus(1, ChronoUnit.MONTHS)
Вместо:
date.plusDays(30)
date1.toEpochDay() === date2.toEpochDay()
const maxDay =
date.lengthOfMonth()
const iso =
LocalDate.from(hijrahDate)
const chronoDate = hijrahDate
const year =
hijrahDate.get(
ChronoField.YEAR
)
HijrahDate хранит дату не как строку и не как набор
независимых полей, а как количество дней относительно эпохи. Это
обеспечивает:
const json =
JSON.stringify({
date: date.toString()
})
console.log(json)
const parsed =
HijrahDate.from(
DateTimeFormatter
.ISO_LOCAL_DATE
.parse('1445-09-01')
)