diff --git a/.circleci/config.yml b/.circleci/config.yml
index ac4c872bfbe..1f65571d3b7 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -77,11 +77,25 @@ commands:
--cache-control "public,max-age=31536000,immutable" \
--exclude "*.html" --exclude "*.rsc" --exclude "*.txt" --exclude "*.json" --exclude "*.md" --exclude "*.xml"
- run:
- name: Copy HTML and text files to S3
+ name: Copy HTML and data files to S3
command: |
aws s3 cp /tmp/dist/s2-docs/<< parameters.dir >> << parameters.bucket >> --recursive \
--cache-control "public,max-age=300,stale-while-revalidate=300" \
- --exclude "*" --include "*.html" --include "*.txt" --include "*.json" --include "*.md" --include "*.xml"
+ --exclude "*" --include "*.html" --include "*.json" --include "*.xml"
+ - run:
+ name: Copy Markdown files to S3
+ command: |
+ aws s3 cp /tmp/dist/s2-docs/<< parameters.dir >> << parameters.bucket >> --recursive \
+ --cache-control "public,max-age=300,stale-while-revalidate=300" \
+ --content-type "text/markdown;charset=utf-8" \
+ --exclude "*" --include "*.md"
+ - run:
+ name: Copy text files to S3
+ command: |
+ aws s3 cp /tmp/dist/s2-docs/<< parameters.dir >> << parameters.bucket >> --recursive \
+ --cache-control "public,max-age=300,stale-while-revalidate=300" \
+ --content-type "text/plain;charset=utf-8" \
+ --exclude "*" --include "*.txt"
- run:
name: Copy RSC files to S3
command: |
diff --git a/packages/@react-spectrum/s2/chromatic/Accordion.stories.tsx b/packages/@react-spectrum/s2/chromatic/Accordion.stories.tsx
index 34feeb88b57..cc3f85a6447 100644
--- a/packages/@react-spectrum/s2/chromatic/Accordion.stories.tsx
+++ b/packages/@react-spectrum/s2/chromatic/Accordion.stories.tsx
@@ -138,7 +138,7 @@ export const WithActionButton: Story = {
Files
-
+
Files content
@@ -149,7 +149,7 @@ export const WithActionButton: Story = {
People
-
+
diff --git a/packages/@react-spectrum/s2/chromatic/DropZone.stories.tsx b/packages/@react-spectrum/s2/chromatic/DropZone.stories.tsx
index 14a13f73f36..d9df5f5c865 100644
--- a/packages/@react-spectrum/s2/chromatic/DropZone.stories.tsx
+++ b/packages/@react-spectrum/s2/chromatic/DropZone.stories.tsx
@@ -43,7 +43,7 @@ const ExampleRender = (args: DropZoneProps): ReactElement => {
- Drag and drop your file
+ Drag or paste your file
Or, select a file from your computer
@@ -72,7 +72,7 @@ const ExampleWithFileTriggerRender = (args: DropZoneProps): ReactElement => {
- Drag and drop your file
+ Drag or paste your file
Or, select a file from your computer
@@ -108,7 +108,7 @@ const LongBannerRender = (args: DropZoneProps): ReactElement => {
- Drag and drop your file
+ Drag or paste your file
Or, select a file from your computer
@@ -172,7 +172,7 @@ const GradientExample = (args: DropZoneProps): ReactElement => {
- Drag and drop your file
+ Drag or paste your file
Or, select a file from your computer
diff --git a/packages/@react-spectrum/s2/stories/Accordion.stories.tsx b/packages/@react-spectrum/s2/stories/Accordion.stories.tsx
index 2d38fedbec3..e39dbe0ffd0 100644
--- a/packages/@react-spectrum/s2/stories/Accordion.stories.tsx
+++ b/packages/@react-spectrum/s2/stories/Accordion.stories.tsx
@@ -217,7 +217,7 @@ export const WithActionButton: Story = {
Files
-
+
Files content
@@ -228,7 +228,7 @@ export const WithActionButton: Story = {
People
-
+
diff --git a/packages/@react-spectrum/s2/stories/DropZone.stories.tsx b/packages/@react-spectrum/s2/stories/DropZone.stories.tsx
index 5c22ff85c27..cd7fa767637 100644
--- a/packages/@react-spectrum/s2/stories/DropZone.stories.tsx
+++ b/packages/@react-spectrum/s2/stories/DropZone.stories.tsx
@@ -52,7 +52,7 @@ const ExampleRender = (args: DropZoneProps): ReactElement => {
- Drag and drop your file
+ Drag or paste your file
Or, select a file from your computer
@@ -81,7 +81,7 @@ const ExampleWithFileTriggerRender = (args: DropZoneProps): ReactElement => {
- Drag and drop your file
+ Drag or paste your file
Or, select a file from your computer
@@ -117,7 +117,7 @@ const LongBannerRender = (args: DropZoneProps): ReactElement => {
- Drag and drop your file
+ Drag or paste your file
Or, select a file from your computer
@@ -146,7 +146,7 @@ const GradientRender = (args: DropZoneProps): ReactElement => {
- Drag and drop your file
+ Drag or paste your file
Or, select a file from your computer
diff --git a/packages/dev/s2-docs/pages/react-aria/Calendar.mdx b/packages/dev/s2-docs/pages/react-aria/Calendar.mdx
index e0fd2497e3f..3941ebaa1d4 100644
--- a/packages/dev/s2-docs/pages/react-aria/Calendar.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/Calendar.mdx
@@ -83,8 +83,8 @@ import {Calendar} from 'vanilla-starter/Calendar';
```tsx render
"use client";
-import type {AnyCalendarDate} from '@internationalized/date';
-import {CalendarDate, startOfWeek, toCalendar, GregorianCalendar} from '@internationalized/date';
+import type {AnyCalendarDate, Calendar as ICalendar} from '@internationalized/date';
+import {CalendarDate, startOfWeek, GregorianCalendar} from '@internationalized/date';
import {Calendar} from 'vanilla-starter/Calendar';
export default function Example() {
@@ -100,45 +100,66 @@ export default function Example() {
// See @internationalized/date docs linked above.
///- begin collapse -///
class Custom454 extends GregorianCalendar {
- weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];
- getDaysInMonth(date) {
- return this.weekPattern[date.month - 1] * 7;
+ // The anchor date, in Gregorian calendar.
+ // The anchor date is a date that occurs in the first week of the first month of every fiscal year.
+ anchorDate = new CalendarDate(2001, 2, 4);
+
+ private getYear(year: number): [CalendarDate, number[]] {
+ let anchor = this.anchorDate.set({year});
+ let startOfYear = startOfWeek(anchor, 'en', 'sun');
+ let isBigYear = !startOfYear.add({weeks: 53}).compare(anchor.add({years: 1}));
+ let weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, isBigYear ? 5 : 4];
+ return [startOfYear, weekPattern];
+ }
+
+ getDaysInMonth(date: AnyCalendarDate): number {
+ let [, weekPattern] = this.getYear(date.year);
+ return weekPattern[date.month - 1] * 7;
}
fromJulianDay(jd: number): CalendarDate {
let gregorian = super.fromJulianDay(jd);
+ let year = gregorian.year;
+
+ let [monthStart, weekPattern] = this.getYear(year);
+ if (gregorian.compare(monthStart) < 0) {
+ year--;
+ [monthStart, weekPattern] = this.getYear(year);
+ }
- let monthStart = startOfWeek(new CalendarDate(gregorian.year, 1, 1), 'en');
- for (let months = 0; months < this.weekPattern.length; months++) {
- let weeksInMonth = this.weekPattern[months];
- let monthEnd = monthStart.add({weeks: weeksInMonth});
- if (monthEnd.compare(gregorian) > 0) {
+ for (let month = 1; month <= 12; month++) {
+ let weeks = weekPattern[month - 1];
+ let nextMonth = monthStart.add({weeks});
+ if (nextMonth.compare(gregorian) > 0) {
let days = gregorian.compare(monthStart);
- return new CalendarDate(this, monthStart.year, months + 1, days + 1);
+ return new CalendarDate(this, year, month, days + 1);
}
- monthStart = monthEnd;
+ monthStart = nextMonth;
}
- throw Error('Date is not in any month somehow!');
+ throw new Error('date not found');
}
toJulianDay(date: AnyCalendarDate): number {
- let monthStart = startOfWeek(new CalendarDate(date.year, 1, 1), 'en');
+ let [monthStart, weekPattern] = this.getYear(date.year);
for (let month = 1; month < date.month; month++) {
- monthStart = monthStart.add({weeks: this.weekPattern[month - 1]});
+ monthStart = monthStart.add({weeks: weekPattern[month - 1]});
}
let gregorian = monthStart.add({days: date.day - 1});
return super.toJulianDay(gregorian);
}
- getFormattableMonth(date) {
- let gregorian = toCalendar(date, new GregorianCalendar());
- return gregorian.set({month: date.month, day: 1});
+ getFormattableMonth(date: AnyCalendarDate): CalendarDate {
+ let anchorMonth = this.anchorDate.month - 1;
+ let dateMonth = date.month - 1;
+ let month = ((anchorMonth + dateMonth) % 12) + 1;
+ let year = anchorMonth + dateMonth >= 12 ? date.year + 1 : date.year;
+ return new CalendarDate(year, month, 1);
}
- isEqual(other) {
- return other instanceof Custom454;
+ isEqual(other: ICalendar): boolean {
+ return other instanceof Custom454 && other.anchorDate.compare(this.anchorDate) === 0;
}
}
///- end collapse -///
diff --git a/packages/dev/s2-docs/pages/react-aria/RangeCalendar.mdx b/packages/dev/s2-docs/pages/react-aria/RangeCalendar.mdx
index bead2451c0d..a5cc8075980 100644
--- a/packages/dev/s2-docs/pages/react-aria/RangeCalendar.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/RangeCalendar.mdx
@@ -93,8 +93,8 @@ import {RangeCalendar} from 'vanilla-starter/RangeCalendar';
```tsx render
"use client";
-import type {AnyCalendarDate} from '@internationalized/date';
-import {CalendarDate, startOfWeek, toCalendar, GregorianCalendar} from '@internationalized/date';
+import type {AnyCalendarDate, Calendar} from '@internationalized/date';
+import {CalendarDate, startOfWeek, GregorianCalendar} from '@internationalized/date';
import {RangeCalendar} from 'vanilla-starter/RangeCalendar';
export default function Example() {
@@ -110,45 +110,66 @@ export default function Example() {
// See @internationalized/date docs linked above.
///- begin collapse -///
class Custom454 extends GregorianCalendar {
- weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];
- getDaysInMonth(date) {
- return this.weekPattern[date.month - 1] * 7;
+ // The anchor date, in Gregorian calendar.
+ // The anchor date is a date that occurs in the first week of the first month of every fiscal year.
+ anchorDate = new CalendarDate(2001, 2, 4);
+
+ private getYear(year: number): [CalendarDate, number[]] {
+ let anchor = this.anchorDate.set({year});
+ let startOfYear = startOfWeek(anchor, 'en', 'sun');
+ let isBigYear = !startOfYear.add({weeks: 53}).compare(anchor.add({years: 1}));
+ let weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, isBigYear ? 5 : 4];
+ return [startOfYear, weekPattern];
+ }
+
+ getDaysInMonth(date: AnyCalendarDate): number {
+ let [, weekPattern] = this.getYear(date.year);
+ return weekPattern[date.month - 1] * 7;
}
fromJulianDay(jd: number): CalendarDate {
let gregorian = super.fromJulianDay(jd);
+ let year = gregorian.year;
+
+ let [monthStart, weekPattern] = this.getYear(year);
+ if (gregorian.compare(monthStart) < 0) {
+ year--;
+ [monthStart, weekPattern] = this.getYear(year);
+ }
- let monthStart = startOfWeek(new CalendarDate(gregorian.year, 1, 1), 'en');
- for (let months = 0; months < this.weekPattern.length; months++) {
- let weeksInMonth = this.weekPattern[months];
- let monthEnd = monthStart.add({weeks: weeksInMonth});
- if (monthEnd.compare(gregorian) > 0) {
+ for (let month = 1; month <= 12; month++) {
+ let weeks = weekPattern[month - 1];
+ let nextMonth = monthStart.add({weeks});
+ if (nextMonth.compare(gregorian) > 0) {
let days = gregorian.compare(monthStart);
- return new CalendarDate(this, monthStart.year, months + 1, days + 1);
+ return new CalendarDate(this, year, month, days + 1);
}
- monthStart = monthEnd;
+ monthStart = nextMonth;
}
- throw Error('Date is not in any month somehow!');
+ throw new Error('date not found');
}
toJulianDay(date: AnyCalendarDate): number {
- let monthStart = startOfWeek(new CalendarDate(date.year, 1, 1), 'en');
+ let [monthStart, weekPattern] = this.getYear(date.year);
for (let month = 1; month < date.month; month++) {
- monthStart = monthStart.add({weeks: this.weekPattern[month - 1]});
+ monthStart = monthStart.add({weeks: weekPattern[month - 1]});
}
let gregorian = monthStart.add({days: date.day - 1});
return super.toJulianDay(gregorian);
}
- getFormattableMonth(date) {
- let gregorian = toCalendar(date, new GregorianCalendar());
- return gregorian.set({month: date.month, day: 1});
+ getFormattableMonth(date: AnyCalendarDate): CalendarDate {
+ let anchorMonth = this.anchorDate.month - 1;
+ let dateMonth = date.month - 1;
+ let month = ((anchorMonth + dateMonth) % 12) + 1;
+ let year = anchorMonth + dateMonth >= 12 ? date.year + 1 : date.year;
+ return new CalendarDate(year, month, 1);
}
- isEqual(other) {
- return other instanceof Custom454;
+ isEqual(other: Calendar): boolean {
+ return other instanceof Custom454 && other.anchorDate.compare(this.anchorDate) === 0;
}
}
///- end collapse -///
diff --git a/packages/dev/s2-docs/pages/react-aria/internationalized/date/Calendar.mdx b/packages/dev/s2-docs/pages/react-aria/internationalized/date/Calendar.mdx
index b057698d818..fae8a638eec 100644
--- a/packages/dev/s2-docs/pages/react-aria/internationalized/date/Calendar.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/internationalized/date/Calendar.mdx
@@ -125,36 +125,55 @@ The following code is an example of how you might implement a custom 4-5-4 calen
import type {AnyCalendarDate, Calendar} from '@internationalized/date';
import {CalendarDate, GregorianCalendar, startOfWeek} from '@internationalized/date';
-const weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];
-
+// This calendar gives each month a 4-5-4 week pattern, with February as the first month of the year.
+// This means that in this calendar, 2024-01-01 translates to 2024-02-04 in the Gregorian calendar.
+// Months begin on day 1, and go through 7*weeksInMonth days, ending on either the 28th or 35th day of the month.
class Custom454 extends GregorianCalendar {
- // Months always have either 4 or 5 full weeks.
- getDaysInMonth(date) {
+ // The anchor date, in Gregorian calendar.
+ // The anchor date is a date that occurs in the first week of the first month of every fiscal year.
+ anchorDate = new CalendarDate(2001, 2, 4);
+
+ private getYear(year: number): [CalendarDate, number[]] {
+ let anchor = this.anchorDate.set({year});
+ let startOfYear = startOfWeek(anchor, 'en', 'sun');
+ let isBigYear = !startOfYear.add({weeks: 53}).compare(anchor.add({years: 1}));
+ let weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, isBigYear ? 5 : 4];
+ return [startOfYear, weekPattern];
+ }
+
+ getDaysInMonth(date: AnyCalendarDate): number {
+ // Months always have either 4 or 5 full weeks.
+ let [, weekPattern] = this.getYear(date.year);
return weekPattern[date.month - 1] * 7;
}
- // Enable conversion between calendar systems.
fromJulianDay(jd: number): CalendarDate {
let gregorian = super.fromJulianDay(jd);
+ let year = gregorian.year;
+
+ let [monthStart, weekPattern] = this.getYear(year);
+ if (gregorian.compare(monthStart) < 0) {
+ year--;
+ [monthStart, weekPattern] = this.getYear(year);
+ }
// Start from the beginning of the first week of the gregorian year
// and add weeks until we find the month.
- let monthStart = startOfWeek(new CalendarDate(gregorian.year, 1, 1), 'en');
- for (let months = 0; months < weekPattern.length; months++) {
- let weeksInMonth = weekPattern[months];
- let monthEnd = monthStart.add({weeks: weeksInMonth});
- if (monthEnd.compare(gregorian) > 0) {
+ for (let month = 1; month <= 12; month++) {
+ let weeks = weekPattern[month - 1];
+ let nextMonth = monthStart.add({weeks});
+ if (nextMonth.compare(gregorian) > 0) {
let days = gregorian.compare(monthStart);
- return new CalendarDate(this, monthStart.year, months + 1, days + 1);
+ return new CalendarDate(this, year, month, days + 1);
}
- monthStart = monthEnd;
+ monthStart = nextMonth;
}
- throw Error('Date is not in any month somehow!');
+ throw new Error('date not found');
}
toJulianDay(date: AnyCalendarDate): number {
- let monthStart = startOfWeek(new CalendarDate(date.year, 1, 1), 'en');
+ let [monthStart, weekPattern] = this.getYear(date.year);
for (let month = 1; month < date.month; month++) {
monthStart = monthStart.add({weeks: weekPattern[month - 1]});
}
@@ -163,8 +182,16 @@ class Custom454 extends GregorianCalendar {
return super.toJulianDay(gregorian);
}
- isEqual(other: Calendar) {
- return other instanceof Custom454;
+ getFormattableMonth(date: AnyCalendarDate): CalendarDate {
+ let anchorMonth = this.anchorDate.month - 1;
+ let dateMonth = date.month - 1;
+ let month = ((anchorMonth + dateMonth) % 12) + 1;
+ let year = anchorMonth + dateMonth >= 12 ? date.year + 1 : date.year;
+ return new CalendarDate(year, month, 1);
+ }
+
+ isEqual(other: Calendar): boolean {
+ return other instanceof Custom454 && other.anchorDate.compare(this.anchorDate) === 0;
}
}
```
diff --git a/packages/dev/s2-docs/pages/s2/Calendar.mdx b/packages/dev/s2-docs/pages/s2/Calendar.mdx
index 00c8e6c0796..06ff974e152 100644
--- a/packages/dev/s2-docs/pages/s2/Calendar.mdx
+++ b/packages/dev/s2-docs/pages/s2/Calendar.mdx
@@ -74,8 +74,8 @@ import {parseDate} from '@internationalized/date';
```tsx render
"use client";
-import type {AnyCalendarDate} from '@internationalized/date';
-import {CalendarDate, startOfWeek, toCalendar, GregorianCalendar} from '@internationalized/date';
+import type {AnyCalendarDate, Calendar as ICalendar} from '@internationalized/date';
+import {CalendarDate, startOfWeek, GregorianCalendar} from '@internationalized/date';
import {Calendar} from '@react-spectrum/s2';
export default function Example() {
@@ -91,45 +91,66 @@ export default function Example() {
// See @internationalized/date docs linked above.
///- begin collapse -///
class Custom454 extends GregorianCalendar {
- weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];
- getDaysInMonth(date) {
- return this.weekPattern[date.month - 1] * 7;
+ // The anchor date, in Gregorian calendar.
+ // The anchor date is a date that occurs in the first week of the first month of every fiscal year.
+ anchorDate = new CalendarDate(2001, 2, 4);
+
+ private getYear(year: number): [CalendarDate, number[]] {
+ let anchor = this.anchorDate.set({year});
+ let startOfYear = startOfWeek(anchor, 'en', 'sun');
+ let isBigYear = !startOfYear.add({weeks: 53}).compare(anchor.add({years: 1}));
+ let weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, isBigYear ? 5 : 4];
+ return [startOfYear, weekPattern];
+ }
+
+ getDaysInMonth(date: AnyCalendarDate): number {
+ let [, weekPattern] = this.getYear(date.year);
+ return weekPattern[date.month - 1] * 7;
}
fromJulianDay(jd: number): CalendarDate {
let gregorian = super.fromJulianDay(jd);
+ let year = gregorian.year;
+
+ let [monthStart, weekPattern] = this.getYear(year);
+ if (gregorian.compare(monthStart) < 0) {
+ year--;
+ [monthStart, weekPattern] = this.getYear(year);
+ }
- let monthStart = startOfWeek(new CalendarDate(gregorian.year, 1, 1), 'en');
- for (let months = 0; months < this.weekPattern.length; months++) {
- let weeksInMonth = this.weekPattern[months];
- let monthEnd = monthStart.add({weeks: weeksInMonth});
- if (monthEnd.compare(gregorian) > 0) {
+ for (let month = 1; month <= 12; month++) {
+ let weeks = weekPattern[month - 1];
+ let nextMonth = monthStart.add({weeks});
+ if (nextMonth.compare(gregorian) > 0) {
let days = gregorian.compare(monthStart);
- return new CalendarDate(this, monthStart.year, months + 1, days + 1);
+ return new CalendarDate(this, year, month, days + 1);
}
- monthStart = monthEnd;
+ monthStart = nextMonth;
}
- throw Error('Date is not in any month somehow!');
+ throw new Error('date not found');
}
toJulianDay(date: AnyCalendarDate): number {
- let monthStart = startOfWeek(new CalendarDate(date.year, 1, 1), 'en');
+ let [monthStart, weekPattern] = this.getYear(date.year);
for (let month = 1; month < date.month; month++) {
- monthStart = monthStart.add({weeks: this.weekPattern[month - 1]});
+ monthStart = monthStart.add({weeks: weekPattern[month - 1]});
}
let gregorian = monthStart.add({days: date.day - 1});
return super.toJulianDay(gregorian);
}
- getFormattableMonth(date) {
- let gregorian = toCalendar(date, new GregorianCalendar());
- return gregorian.set({month: date.month, day: 1});
+ getFormattableMonth(date: AnyCalendarDate): CalendarDate {
+ let anchorMonth = this.anchorDate.month - 1;
+ let dateMonth = date.month - 1;
+ let month = ((anchorMonth + dateMonth) % 12) + 1;
+ let year = anchorMonth + dateMonth >= 12 ? date.year + 1 : date.year;
+ return new CalendarDate(year, month, 1);
}
- isEqual(other) {
- return other instanceof Custom454;
+ isEqual(other: ICalendar): boolean {
+ return other instanceof Custom454 && other.anchorDate.compare(this.anchorDate) === 0;
}
}
///- end collapse -///
diff --git a/packages/dev/s2-docs/pages/s2/RangeCalendar.mdx b/packages/dev/s2-docs/pages/s2/RangeCalendar.mdx
index 8e10cecc38e..e3247d9fe6b 100644
--- a/packages/dev/s2-docs/pages/s2/RangeCalendar.mdx
+++ b/packages/dev/s2-docs/pages/s2/RangeCalendar.mdx
@@ -86,8 +86,8 @@ import {parseDate} from '@internationalized/date';
```tsx render
"use client";
-import type {AnyCalendarDate} from '@internationalized/date';
-import {CalendarDate, startOfWeek, toCalendar, GregorianCalendar} from '@internationalized/date';
+import type {AnyCalendarDate, Calendar} from '@internationalized/date';
+import {CalendarDate, startOfWeek, GregorianCalendar} from '@internationalized/date';
import {RangeCalendar} from '@react-spectrum/s2';
export default function Example() {
@@ -103,45 +103,66 @@ export default function Example() {
// See @internationalized/date docs linked above.
///- begin collapse -///
class Custom454 extends GregorianCalendar {
- weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];
- getDaysInMonth(date) {
- return this.weekPattern[date.month - 1] * 7;
+ // The anchor date, in Gregorian calendar.
+ // The anchor date is a date that occurs in the first week of the first month of every fiscal year.
+ anchorDate = new CalendarDate(2001, 2, 4);
+
+ private getYear(year: number): [CalendarDate, number[]] {
+ let anchor = this.anchorDate.set({year});
+ let startOfYear = startOfWeek(anchor, 'en', 'sun');
+ let isBigYear = !startOfYear.add({weeks: 53}).compare(anchor.add({years: 1}));
+ let weekPattern = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, isBigYear ? 5 : 4];
+ return [startOfYear, weekPattern];
+ }
+
+ getDaysInMonth(date: AnyCalendarDate): number {
+ let [, weekPattern] = this.getYear(date.year);
+ return weekPattern[date.month - 1] * 7;
}
fromJulianDay(jd: number): CalendarDate {
let gregorian = super.fromJulianDay(jd);
+ let year = gregorian.year;
+
+ let [monthStart, weekPattern] = this.getYear(year);
+ if (gregorian.compare(monthStart) < 0) {
+ year--;
+ [monthStart, weekPattern] = this.getYear(year);
+ }
- let monthStart = startOfWeek(new CalendarDate(gregorian.year, 1, 1), 'en');
- for (let months = 0; months < this.weekPattern.length; months++) {
- let weeksInMonth = this.weekPattern[months];
- let monthEnd = monthStart.add({weeks: weeksInMonth});
- if (monthEnd.compare(gregorian) > 0) {
+ for (let month = 1; month <= 12; month++) {
+ let weeks = weekPattern[month - 1];
+ let nextMonth = monthStart.add({weeks});
+ if (nextMonth.compare(gregorian) > 0) {
let days = gregorian.compare(monthStart);
- return new CalendarDate(this, monthStart.year, months + 1, days + 1);
+ return new CalendarDate(this, year, month, days + 1);
}
- monthStart = monthEnd;
+ monthStart = nextMonth;
}
- throw Error('Date is not in any month somehow!');
+ throw new Error('date not found');
}
toJulianDay(date: AnyCalendarDate): number {
- let monthStart = startOfWeek(new CalendarDate(date.year, 1, 1), 'en');
+ let [monthStart, weekPattern] = this.getYear(date.year);
for (let month = 1; month < date.month; month++) {
- monthStart = monthStart.add({weeks: this.weekPattern[month - 1]});
+ monthStart = monthStart.add({weeks: weekPattern[month - 1]});
}
let gregorian = monthStart.add({days: date.day - 1});
return super.toJulianDay(gregorian);
}
- getFormattableMonth(date) {
- let gregorian = toCalendar(date, new GregorianCalendar());
- return gregorian.set({month: date.month, day: 1});
+ getFormattableMonth(date: AnyCalendarDate): CalendarDate {
+ let anchorMonth = this.anchorDate.month - 1;
+ let dateMonth = date.month - 1;
+ let month = ((anchorMonth + dateMonth) % 12) + 1;
+ let year = anchorMonth + dateMonth >= 12 ? date.year + 1 : date.year;
+ return new CalendarDate(year, month, 1);
}
- isEqual(other) {
- return other instanceof Custom454;
+ isEqual(other: Calendar): boolean {
+ return other instanceof Custom454 && other.anchorDate.compare(this.anchorDate) === 0;
}
}
///- end collapse -///