diff --git a/src/chronology/application/DateConverterFormChange.test.ts b/src/chronology/application/DateConverterFormChange.test.ts
index ac9e65e9a..f26f5026f 100644
--- a/src/chronology/application/DateConverterFormChange.test.ts
+++ b/src/chronology/application/DateConverterFormChange.test.ts
@@ -51,7 +51,7 @@ it('handles setToGregorianDate scenario correctly', () => {
setFormData: mockSetFormData,
setScenario,
})
- expect(mockDateConverter.setToGregorianDate).toBeCalledWith(-309, 3, 29)
+ expect(mockDateConverter.setToGregorianDate).toBeCalledWith(-310, 3, 29)
})
it('handles setToJulianDate scenario correctly', () => {
diff --git a/src/chronology/application/DateSelection.tsx b/src/chronology/application/DateSelection.tsx
index 13cff382c..4a3fce987 100644
--- a/src/chronology/application/DateSelection.tsx
+++ b/src/chronology/application/DateSelection.tsx
@@ -14,6 +14,7 @@ import {
} from 'chronology/ui/DateEditor/DateSelectionInput'
import useDateSelectionState, {
DateEditorStateProps,
+ DateSelectionState,
} from 'chronology/application/DateSelectionState'
type Props = {
@@ -30,6 +31,28 @@ interface DateEditorProps extends DateEditorStateProps {
isDisplayed: boolean
}
+function getSelectedDateAndValidation(
+ state: DateSelectionState,
+ savedDate?: MesopotamianDate
+): { selectedDate?: MesopotamianDate; isSelectedDateValid: boolean } {
+ let isSelectedDateValid: boolean
+ let selectedDate: MesopotamianDate | undefined
+ try {
+ selectedDate = state.getDate()
+ const dateString = selectedDate.toString()
+ const isDatesNotSame =
+ savedDate === undefined || dateString !== savedDate.toString()
+ const isDateEmpty = dateString.replaceAll('SE', '') !== ''
+ const isAssyrianDateNotEmpty =
+ !state.isAssyrianDate || dateString !== '∅.∅.1'
+ isSelectedDateValid =
+ isDateEmpty && isAssyrianDateNotEmpty && isDatesNotSame
+ } catch {
+ isSelectedDateValid = false
+ }
+ return { selectedDate, isSelectedDateValid }
+}
+
export function DateEditor({
date,
setDate,
@@ -55,27 +78,50 @@ export function DateEditor({
const dateOptionsInput = DateOptionsInput({ ...state })
const dateInputGroups = DateInputGroups({ ...state })
- const saveButton = (
+ const deleteButton = (
)
- const deleteButton = (
+ const { selectedDate, isSelectedDateValid } = getSelectedDateAndValidation(
+ state,
+ date
+ )
+
+ const saveButton = (
)
+ const savedDateDisplay = date ? (
+ <>
+ Saved date
+
+ >
+ ) : (
+ ''
+ )
+ const selectedDateDisplay =
+ selectedDate && isSelectedDateValid ? (
+ <>
+ Selected date
+
+ >
+ ) : (
+ ''
+ )
+
const popover = (
{dateOptionsInput}
{dateInputGroups}
+ {savedDateDisplay}
+ {selectedDateDisplay}
{date && deleteButton}
{saveButton}
Saving...
diff --git a/src/chronology/domain/Date.test.ts b/src/chronology/domain/Date.test.ts
index 9339b703b..5cdf8fc42 100644
--- a/src/chronology/domain/Date.test.ts
+++ b/src/chronology/domain/Date.test.ts
@@ -109,7 +109,7 @@ describe('MesopotamianDate', () => {
true
)
expect(date.toString()).toBe(
- '12.V.10 SE (30 August 302 BCE PJC | 25 August 301 BCE PGC)'
+ '12.V.10 SE (30 August 302 BCE PJC | 25 August 302 BCE PGC)'
)
})
@@ -123,7 +123,7 @@ describe('MesopotamianDate', () => {
true
)
expect(date.toString()).toBe(
- '∅.V.10 SE (ca. 19 August 302 BCE PJC | ca. 14 August 301 BCE PGC)'
+ '∅.V.10 SE (ca. 19 August 302 BCE PJC | ca. 14 August 302 BCE PGC)'
)
})
@@ -137,7 +137,7 @@ describe('MesopotamianDate', () => {
true
)
expect(date.toString()).toBe(
- '12.∅.10 SE (ca. 4 May 302 BCE PJC | ca. 29 April 301 BCE PGC)'
+ '12.∅.10 SE (ca. 4 May 302 BCE PJC | ca. 29 April 302 BCE PGC)'
)
})
@@ -164,7 +164,7 @@ describe('MesopotamianDate', () => {
false
)
expect(date.toString()).toBe(
- '12.V.10 Darius I (11 August 512 BCE PJC | 5 August 511 BCE PGC)'
+ '12.V.10 Darius I (11 August 512 BCE PJC | 5 August 512 BCE PGC)'
)
})
@@ -179,7 +179,7 @@ describe('MesopotamianDate', () => {
false
)
expect(date.toString()).toBe(
- '∅.V.10 Darius I (ca. 31 July 512 BCE PJC | ca. 25 July 511 BCE PGC)'
+ '∅.V.10 Darius I (ca. 31 July 512 BCE PJC | ca. 25 July 512 BCE PGC)'
)
})
@@ -194,7 +194,7 @@ describe('MesopotamianDate', () => {
false
)
expect(date.toString()).toBe(
- '12.∅.10 Darius I (ca. 16 April 512 BCE PJC | ca. 10 April 511 BCE PGC)'
+ '12.∅.10 Darius I (ca. 16 April 512 BCE PJC | ca. 10 April 512 BCE PGC)'
)
})
@@ -209,7 +209,7 @@ describe('MesopotamianDate', () => {
false
)
expect(date.toString()).toBe(
- '∅.V.10 Darius I (ca. 31 July 512 BCE PJC | ca. 25 July 511 BCE PGC)'
+ '∅.V.10 Darius I (ca. 31 July 512 BCE PJC | ca. 25 July 512 BCE PGC)'
)
})
diff --git a/src/chronology/domain/DateBase.ts b/src/chronology/domain/DateBase.ts
index 09e276f46..47261a9fd 100644
--- a/src/chronology/domain/DateBase.ts
+++ b/src/chronology/domain/DateBase.ts
@@ -95,23 +95,19 @@ export class MesopotamianDateBase {
}
toModernDate(calendar: 'Julian' | 'Gregorian' = 'Julian'): string {
- const { year, month, day, isApproximate } = this.getDateApproximation()
const dateProps = {
- year,
- month,
- day,
- isApproximate,
+ ...this.getDateApproximation(),
calendar,
}
let julianDate = ''
- if (this.isSeleucidEraApplicable(year)) {
+ if (this.isSeleucidEraApplicable(dateProps.year)) {
julianDate = this.seleucidToModernDate(dateProps)
} else if (this.isNabonassarEraApplicable()) {
julianDate = this.getNabonassarEraDate(dateProps)
} else if (this.isAssyrianDateApplicable()) {
julianDate = this.getAssyrianDate({ calendar: 'Julian' })
} else if (this.isKingDateApplicable()) {
- julianDate = this.kingToModernDate({ year, calendar: 'Julian' })
+ julianDate = this.kingToModernDate({ ...dateProps, calendar: 'Julian' })
}
return julianDate
}
@@ -144,24 +140,14 @@ export class MesopotamianDateBase {
day: number
isApproximate: boolean
} {
- let year = parseInt(this.year.value)
- let month = parseInt(this.month.value)
- let day = parseInt(this.day.value)
- const isApproximate = this.isApproximate()
- if (isNaN(month)) {
- month = 1
- }
- if (isNaN(day)) {
- day = 1
- }
- if (isNaN(year)) {
- year = -1
- }
+ const year = parseInt(this.year.value)
+ const month = parseInt(this.month.value)
+ const day = parseInt(this.day.value)
return {
- year,
- month,
- day,
- isApproximate: isApproximate,
+ year: isNaN(year) ? -1 : year,
+ month: isNaN(month) ? 1 : month,
+ day: isNaN(day) ? 1 : day,
+ isApproximate: this.isApproximate(),
}
}
@@ -221,6 +207,7 @@ export class MesopotamianDateBase {
}
return ''
}
+
private kingToModernDate({
year,
calendar = 'Julian',
diff --git a/src/chronology/domain/DateConverter.test.ts b/src/chronology/domain/DateConverter.test.ts
index 7ff86ecd5..5b46ab542 100644
--- a/src/chronology/domain/DateConverter.test.ts
+++ b/src/chronology/domain/DateConverter.test.ts
@@ -3,8 +3,8 @@ import DateConverter from 'chronology/domain/DateConverter'
const dateJulianEraBegin = {
bcJulianYear: 311,
cjdn: 1607923,
- gregorianYear: -309,
- bcGregorianYear: 310,
+ gregorianYear: -310,
+ bcGregorianYear: 311,
gregorianMonth: 3,
gregorianDay: 29,
julianDay: 3,
@@ -23,8 +23,8 @@ const dateJulianEraBegin = {
}
const dateNebuchadnezzarIIY43M12D28 = {
- gregorianYear: -559,
- bcGregorianYear: 560,
+ gregorianYear: -560,
+ bcGregorianYear: 561,
gregorianMonth: 3,
gregorianDay: 28,
julianYear: -560,
@@ -44,8 +44,8 @@ const dateNebuchadnezzarIIY43M12D28 = {
}
const dateNebuchadnezzarIIY23M10D14 = {
- gregorianYear: -580,
- bcGregorianYear: 581,
+ gregorianYear: -581,
+ bcGregorianYear: 582,
gregorianMonth: 12,
gregorianDay: 28,
julianYear: -580,
@@ -65,8 +65,8 @@ const dateNebuchadnezzarIIY23M10D14 = {
}
const dateSeleucidY100M12D26 = {
- gregorianYear: -209,
- bcGregorianYear: 210,
+ gregorianYear: -210,
+ bcGregorianYear: 211,
gregorianMonth: 3,
gregorianDay: 30,
julianYear: -210,
@@ -89,7 +89,6 @@ const dateSeleucidY100M12D26 = {
describe('DateConverter', () => {
let mesopotamianDate: DateConverter
-
beforeEach(() => {
mesopotamianDate = new DateConverter()
})
@@ -97,7 +96,7 @@ describe('DateConverter', () => {
test('Check initial state', () => {
const expected = dateJulianEraBegin
expect(mesopotamianDate.calendar).toEqual(expected)
- expect(mesopotamianDate.toDateString()).toEqual('29 March 310 BCE PGC')
+ expect(mesopotamianDate.toDateString()).toEqual('29 March 311 BCE PGC')
expect(mesopotamianDate.toDateString('Julian')).toEqual(
'3 April 311 BCE PJC'
)
@@ -105,9 +104,9 @@ describe('DateConverter', () => {
test('Set to Gregorian date', () => {
const expected = dateNebuchadnezzarIIY43M12D28
- mesopotamianDate.setToGregorianDate(-559, 3, 28)
+ mesopotamianDate.setToGregorianDate(-560, 3, 28)
expect(mesopotamianDate.calendar).toEqual(expected)
- expect(mesopotamianDate.toDateString()).toEqual('28 March 560 BCE PGC')
+ expect(mesopotamianDate.toDateString()).toEqual('28 March 561 BCE PGC')
expect(mesopotamianDate.toDateString('Julian')).toEqual(
'3 April 561 BCE PJC'
)
@@ -117,7 +116,7 @@ describe('DateConverter', () => {
const expected = dateNebuchadnezzarIIY43M12D28
mesopotamianDate.setToJulianDate(-560, 4, 3)
expect(mesopotamianDate.calendar).toEqual(expected)
- expect(mesopotamianDate.toDateString()).toEqual('28 March 560 BCE PGC')
+ expect(mesopotamianDate.toDateString()).toEqual('28 March 561 BCE PGC')
expect(mesopotamianDate.toDateString('Julian')).toEqual(
'3 April 561 BCE PJC'
)
@@ -127,7 +126,7 @@ describe('DateConverter', () => {
const expected = dateNebuchadnezzarIIY23M10D14
mesopotamianDate.setToMesopotamianDate('Nebuchadnezzar II', 23, 10, 14)
expect(mesopotamianDate.calendar).toEqual(expected)
- expect(mesopotamianDate.toDateString()).toEqual('28 December 581 BCE PGC')
+ expect(mesopotamianDate.toDateString()).toEqual('28 December 582 BCE PGC')
expect(mesopotamianDate.toDateString('Julian')).toEqual(
'3 January 581 BCE PJC'
)
@@ -137,7 +136,7 @@ describe('DateConverter', () => {
mesopotamianDate.setToSeBabylonianDate(100, 12, 26)
const expected = dateSeleucidY100M12D26
expect(mesopotamianDate.calendar).toEqual(expected)
- expect(mesopotamianDate.toDateString()).toEqual('30 March 210 BCE PGC')
+ expect(mesopotamianDate.toDateString()).toEqual('30 March 211 BCE PGC')
expect(mesopotamianDate.toDateString('Julian')).toEqual(
'3 April 211 BCE PJC'
)
diff --git a/src/chronology/domain/DateConverterCompute.ts b/src/chronology/domain/DateConverterCompute.ts
index 06b2d19ee..1187b4769 100644
--- a/src/chronology/domain/DateConverterCompute.ts
+++ b/src/chronology/domain/DateConverterCompute.ts
@@ -64,7 +64,7 @@ export default class DateConverterCompute {
)
const { quotient: alpha2b, remainder: m0 } = divmod(m1 + 2, 12)
return {
- year: a1 + alpha2b < 1 ? a1 + alpha2b + 1 : a1 + alpha2b,
+ year: a1 + alpha2b < 1 ? a1 + alpha2b : a1 + alpha2b,
month: m0 + 1,
day: Math.floor(epsilon1 / 5) + 1,
}
@@ -111,19 +111,17 @@ export default class DateConverterCompute {
gregorianMonth: number
gregorianDay: number
}): number {
- gregorianYear = gregorianYear < 1 ? gregorianYear - 1 : gregorianYear
- const alpha1 = Math.floor((gregorianMonth - 3) / 12)
- const m1 = (gregorianMonth - 3) % 12
- const a1 = gregorianYear + alpha1
- return (
- 365 * a1 +
- Math.floor(a1 / 4) -
- Math.floor(a1 / 100) +
- Math.floor(a1 / 400) +
- Math.floor((153 * m1 + 2) / 5) +
- gregorianDay +
- 1721119
- )
+ if (gregorianMonth < 3) {
+ gregorianYear -= 1
+ gregorianMonth += 12
+ }
+ gregorianYear = gregorianYear === 0 ? -1 : gregorianYear
+ const monthDays = Math.floor(30.6001 * (gregorianMonth + 1))
+ const century = Math.floor(gregorianYear / 100)
+ const leapYearCorrection = Math.floor(century / 4)
+ const fixedDay = 2 - century + leapYearCorrection
+ const yearDays = Math.floor(365.25 * (gregorianYear + 4716))
+ return Math.floor(fixedDay + gregorianDay + yearDays + monthDays - 1524)
}
computeWeekDay(cjdn: number): number {
diff --git a/src/chronology/ui/DateConverter/DateConverterForm.test.tsx b/src/chronology/ui/DateConverter/DateConverterForm.test.tsx
index 79fa9ccb5..d1c0a92e6 100644
--- a/src/chronology/ui/DateConverter/DateConverterForm.test.tsx
+++ b/src/chronology/ui/DateConverter/DateConverterForm.test.tsx
@@ -62,7 +62,7 @@ describe('DateConverterForm', () => {
expect(screen.getAllByLabelText(/cjdn|lunation/i)).toHaveLength(2)
expect(optionToArray(screen.getByLabelText('Ruler'))).toStrictEqual(29)
expect(screen.getAllByLabelText(/year/i).map(optionToArray)).toStrictEqual([
- 701,
+ 702,
702,
30,
701,
@@ -82,7 +82,7 @@ describe('DateConverterForm', () => {
it('renders initial form values correctly', () => {
render()
- expect(screen.getByLabelText('Year')).toHaveValue('-309')
+ expect(screen.getByLabelText('Year')).toHaveValue('-310')
expect(screen.getByLabelText('Month')).toHaveValue('3')
expect(screen.getByLabelText('Day')).toHaveValue('29')
expect(screen.getByLabelText('Julian Year')).toHaveValue('-310')
@@ -140,7 +140,7 @@ describe('DateConverterForm', () => {
within(screen.getByLabelText('Year')).getByText('300 BCE')
)
})
- expect(screen.getByLabelText('Year')).toHaveValue('-309')
+ expect(screen.getByLabelText('Year')).toHaveValue('-310')
expect(screen.getByLabelText('Month')).toHaveValue('3')
expect(screen.getByLabelText('Day')).toHaveValue('29')
expect(screen.getByLabelText('Julian Year')).toHaveValue('-310')
@@ -164,7 +164,7 @@ describe('DateConverterForm', () => {
fireEvent.click(screen.getByText('Copy JSON'))
})
const expected = {
- gregorianYear: -309,
+ gregorianYear: -310,
gregorianMonth: 3,
gregorianDay: 29,
julianYear: -310,
@@ -176,7 +176,7 @@ describe('DateConverterForm', () => {
seBabylonianYear: 1,
lunationNabonassar: 5395,
bcJulianYear: 311,
- bcGregorianYear: 310,
+ bcGregorianYear: 311,
mesopotamianDay: 1,
mesopotamianMonthLength: 29,
ruler: 'Seleucus I Nicator',
diff --git a/src/chronology/ui/DateConverter/DateConverterForm.tsx b/src/chronology/ui/DateConverter/DateConverterForm.tsx
index 292bb04a0..978183b65 100644
--- a/src/chronology/ui/DateConverter/DateConverterForm.tsx
+++ b/src/chronology/ui/DateConverter/DateConverterForm.tsx
@@ -15,7 +15,6 @@ import { handleDateConverterFormChange } from 'chronology/application/DateConver
// ToDo:
// - Errors:
-// - January & February have issues (both Julean & Gregorian date drifts upon change)
// - Check dates around 1 BCE / CE
// - Fix errors with first and last ruler
diff --git a/src/chronology/ui/DateEditor/DateSelection.test.tsx b/src/chronology/ui/DateEditor/DateSelection.test.tsx
index af0fc2c46..454588cc6 100644
--- a/src/chronology/ui/DateEditor/DateSelection.test.tsx
+++ b/src/chronology/ui/DateEditor/DateSelection.test.tsx
@@ -126,8 +126,11 @@ describe('DateSelection', () => {
act(() => {
fireEvent.click(editButton)
})
+ const yearInput = screen.getByPlaceholderText('Year')
+ await act(async () => {
+ fireEvent.change(yearInput, { target: { value: '189' } })
+ })
const saveButton = screen.getByText('Save')
-
fireEvent.click(saveButton)
const loadingSpinner = screen.getByText('Saving...')
expect(loadingSpinner).toBeInTheDocument()
diff --git a/src/chronology/ui/DateEditor/DatesInTextSelection.test.tsx b/src/chronology/ui/DateEditor/DatesInTextSelection.test.tsx
index 99a778be9..ba13c69fa 100644
--- a/src/chronology/ui/DateEditor/DatesInTextSelection.test.tsx
+++ b/src/chronology/ui/DateEditor/DatesInTextSelection.test.tsx
@@ -44,6 +44,12 @@ describe('DatesInTextSelection', () => {
await act(async () => {
fireEvent.click(addButton)
})
+ const dayInput = screen.getByPlaceholderText('Day')
+ const monthInput = screen.getByPlaceholderText('Month')
+ await act(async () => {
+ fireEvent.change(dayInput, { target: { value: '18' } })
+ fireEvent.change(monthInput, { target: { value: '10' } })
+ })
const saveButton = screen.getByText('Save')
await act(async () => {
fireEvent.click(saveButton)
@@ -62,6 +68,12 @@ describe('DatesInTextSelection', () => {
await act(async () => {
fireEvent.click(editButton)
})
+ const dayInput = screen.getByPlaceholderText('Day')
+ const monthInput = screen.getByPlaceholderText('Month')
+ await act(async () => {
+ fireEvent.change(dayInput, { target: { value: '18' } })
+ fireEvent.change(monthInput, { target: { value: '10' } })
+ })
const saveButton = screen.getByText('Save')
await act(async () => {
fireEvent.click(saveButton)