71 Commits

Author SHA1 Message Date
Tony Parker
63cfcb9bfd
ISO8601 DateComponents format style (#1209)
* ISO8601 DateComponents style

* Add Hashable to ISO8601FormatStyle
2025-04-04 13:58:57 -07:00
Tony Parker
8c87e9eaac
Use the default time zone instead of gmt, to match the previous behavior of ISO8601 calendar (#1229) 2025-03-27 15:35:22 -07:00
Tony Parker
2ea76c322f
Add an HTTP format style for both Date and DateComponents (#1127)
* Add an HTTP format style for both `Date` and `DateComponents`.

* Correct the comments to properly use DateComponents type

* Use default values instead of crashing when formatting date components with missing or invalid fields

* Use 59 seconds instead of 0 for leap second of 60 - this results in being off by only 1 second in this case instead of 59.

* Address some review feedback
2025-03-13 11:39:57 -07:00
Tina L
6cde050fb3
Introduce compatibility behavior of Calendar.date(byAdding:value:to:wrappingComponents) (#1206)
Some app is passing in `value: -9223372036854775808` to the function below, and force unwrapping the result. It then crashes when the force unwrap fails.

```swift
/// - returns: A new date, or nil if a date could not be calculated with the given input.
public func date(byAdding component: Component, value: Int, to date: Date, wrappingComponents: Bool = false) -> Date?
```

This is caused by #1149. Prior to the change, we were using `_CalendarICU`'s implementation, where we truncate the input value to `Int32`, which becomes 0 in this case. That results in us returning the input `date` unchanged.

Now with #1149, we truthfully return `nil` because the calculation cannot be done.

We could restore the old behavior, but that implementation is incorrect. It's also clearly a wrong assumption on the client side. Add a compatibility check and restore the old behavior if needed.

Resolves 145862455
2025-03-12 09:12:30 -07:00
करन मिश्र
be44158fd9
Remove Thai Calendar (#1203)
145890794
2025-03-06 16:24:25 -08:00
Johannes Weiss
601e847faa
always @preconcurrency import Glibc (#1175)
Co-authored-by: Johannes Weiss <johannes@jweiss.io>
2025-03-04 09:25:51 -08:00
करन मिश्र
47e587a9a4
New Calendars (#1171)
Exposed 12 new calendar identifiers
2025-02-17 14:14:27 -08:00
Allan Shortlidge
06ccc4ced6
Revert "New Calendar Identifiers (#1168)" (#1170)
This reverts commit cc6084b366ca29d0fe06f1ac6060d22c45ab876d.
2025-02-13 14:25:55 -08:00
करन मिश्र
cc6084b366
New Calendar Identifiers (#1168)
Exposed identifiers for 12 new calendars
2025-02-13 12:25:36 -08:00
Tony Parker
d72532e0a5
Use _CalendarGregorian for ISO8601 (#1149) 2025-01-30 22:39:16 +00:00
Hristo Staykov
2ef5d97e33
Properly adjust invalid dates in RecurrenceRule enumeration (#1077)
In recurrence rules without a strict matching policy, we'd sometimes come across
dates which don't exist (such as February 29, 2009). When adjusting these dates,
we were passing unadjusted date components. That resulted in adjusted dates with
the highest unspecified component different than the original date. For example,
adjusting February 29, 2009 to match components {month: 2, day: 29} would result
February 29, 2012, instead of Match 1 or February 28 of the same year.

Adjusting the date components (that is, setting the year to 2009 for the example
above) fixes this. This is what we already do in Calendar.dates(byMatching: ...)
2025-01-06 15:06:16 -08:00
Salynn
ffac47bbf5
Fix upper bound in Calendar.RecurrenceRule.recurrences(of:in:) (#1041)
This commit fixes the use of the `in:` bound in
Calendar.RecurrenceRule.recurrences(of:in:) to properly exclude the
upper bound as revealed by #1040.

Co-authored-by: = <=>
2024-11-20 16:30:43 -08:00
Hristo Staykov
8455ab02b5
Calendar.RecurrenceRule: Only match weekday components when filtering by weekday (#1020)
When filtering by weekdays, we match the dates against a set of date components.
These components happened to contain the hour, minute and second components from
the anchor date, so filtering would undo previous expansions by hour, minute and
second.
2024-11-11 13:43:36 -08:00
Hristo Staykov
71d0424e74
Don't skip anchors with strict matching in Calendar.RecurrenceRule. Resolve #881 (#1000)
In recurrence rules that expand days or weekdays in a month, we first use a base
recurrence to calculate "anchors" in the month, and then change the day of month
or weekday to find results. Because the base recurrence used to match the day of
month of the start date, we could miss anchors if matching was set to `.strict`.
This change makes sure that if we know that the day of month is known to change,
we reset it to 1 in the base recurrence. Likewise, we reset the month in case of
leap month.
2024-10-31 23:36:57 -07:00
Hristo Staykov
a92bc21b71
RecurrenceRule: Respect leap months (#1005)
This change makes a fix to `Calendar.RecurrenceRule` with regards to leap months
and adds a few tests to verify correctness. When constructing the base sequence,
we include `isLeapMonth` of the start date in the date components. Before, start
dates falling on a leap month would have been treated the same as dates which do
fall on the non-leap month before.
2024-10-31 22:50:25 -07:00
Hristo Staykov
33abf9c819
Make RecurrenceRule and its friends conform to Hashable (#995)
As agreed in SF-0010. Resolves rdar://136704624
2024-10-23 13:03:03 -07:00
Hristo Staykov
8510e2086d
Performance improvements for Calendar.RecurrenceRule (#981)
The original implementation of `Calendar.RecurrenceRule` expanded recurrences of
dates using the Calendar APIs for matching date components. This would result in
multiple sequences for matching date components even when just a single sequence
would have sufficed, thus requiring more time and memory to complete enumeration

E.g: finding the dates for Thanksgivings (fourth Thursday of each November) took
~4 times as much time using RecurrenceRule when compared to simply matching date
components.

This commit optimizes how we expand dates for recurrences. Instead of creating a
sequence for each value of each component in the recurrence rule, we introduce a
new type of sequence closely resembling Calendar.DatesByMatching, but which also
allows multiple values per date component.
2024-10-22 09:20:32 -07:00
Tina Liu
3cf61a2959
Properly throw in case of numeric overflow in Calendar mathematics (#900)
* Properly `throw` in case of numeric overflow in Calendar mathematics

We have applied multiple different strategies with regard to overflow during calendrical calculation, including capping input `Date` and clipping Julian day calculation with artificial bounds. Those are still insufficient as there are too many paths where numeric overflow may happen.

This patch patches those places by `throw`ing whenever applicable. Also adds fuzzing tests to cover many more Calendar API.

Resolves rdar://133558250

* Review feedback: Adopt typed throw and fix an oversight
* Update tests
2024-09-17 10:01:40 -07:00
Hristo Staykov
79dc3091aa
Add .count and .date properties to Calendar.RecurrenceRule.End (#888)
`Calendar.RecurrenceRule.End` is de-facto an enum, but has been implemented as a
struct so we can more easily extend it in the future without breaking ABI. Sadly
the current API only provides a way to construct the struct, and does not let us
introspect the associated values. This change adds a couple read-only properties
to the struct to address this.

While at it, we also make the struct conform to `CustomStringConvertible`, so it
doesn't leak implementation details when it's printed in the debugger.
2024-09-14 13:54:23 -07:00
Tony Parker
446af5c0c5
Formatting performance improvements (#884) 2024-08-23 14:13:17 -07:00
finagolfin
c15a5e1f5c
[Android] Use the Bionic module in more places (#842)
Also, use `canImport()` wherever importing APIs, reserving `os(Android)` for
platform differences.
2024-08-15 14:34:15 -07:00
Evan Wilde
aecc1b158c
[main] Get Swift-Foundation building against MUSL for Swift Static SDK (#848)
* Get FoundationEssentials building

Adding the missing musl imports to get FoundationEssentials building for
the Swift static SDKs again.

Also providing an option to disable building the macros. The macros
aren't necessary for building the library and will not be run as part of
the static SDK. No need to bloat the SDK or build times further. For
Swift 6, the macros should be provided by the toolchain since the
toolchain and SDK are current revlocked due to swiftmodules.

* Get FoundationInternationalization building

Adding the missing Musl imports to get FoundationInternationalization
building for the static SDK.
2024-08-14 13:34:15 -07:00
Yuta Saito
c82d1673eb
Add WASI platform conditions for libc imports and word size (#776)
* Add `import WASILibc` statements to libc import chains

* Declare wasm32 arch as 32-bit environment

* Switch to _pointerBitWidth for architecture checks

This change switches the architecture checks in Data.swift to use the
_pointerBitWidth instead of the arch() checks for consistency with newer
platforms.
2024-08-02 09:55:56 -07:00
Tina Liu
3d8294a8c2
Calendar.date(from: <DateComponents>) returns incorrect result when year, weekOfYear, yearForWeekOfYear are set. (#765)
Gregorian calendar's implementation for `date(from: <DateComponents>)` is incorrect for a `DateComponents` when `year`, `weekOfYear`, `yearForWeekOfYear` are set. Restore the behavior of `CalendarICU`, where `yearForWeekOfYear` is preferred to `year` when both are set. This would allow the calculation to use the `weekOfYear` field, which is set in the date components, instead an unset `day` field.

Drive-by fix: give `weekdayOrdinal` a higher priority over other week fields when multiple of them are set. This isn't really an issue as this configuration is ambiguous by nature, but doing so makes it consistent with `CalendarICU`'s behavior.

Fixes 130203724
2024-07-25 16:01:57 -07:00
Jeremy Schonfeld
196376b5fd
Use dynamic replacement instead of _typeByName for internationalization upcalls (#756)
* Use dynamic replacement instead of _typeByName for internationalization upcalls

* Make FOUNDATION_FRAMEWORK function non-dynamic

* Fix build failures
2024-07-23 14:43:01 -07:00
Tony Parker
90109a4cf6
Revert formatting performance improvements (#744)
There appears to be some kind of race or memory smash in ICU after these, and we need more time to investigate the full root cause.
2024-07-18 17:43:34 -07:00
Tony Parker
6ee772ba7f
Improve performance of FormatStyle formatting when used in multithreaded context (#719)
* Improve performance of FormatStyle formatting when used in multithreaded context

* Change canImport statement to support newer SDK on older macOS
2024-07-09 10:06:47 -07:00
Saleem Abdulrasool
a7692238a8
FoundationEssentials: initial pass to add Android support (#704)
This adds the necessary guards and includes for the Android modules.
While the module does not compile currently due to nullability
differences (and in some cases missing declarations), this at least
brings the module to a point where we can start working on the errors
and differences to create a maintainable codebase for Android.
2024-06-26 16:00:37 -07:00
Tina Liu
f7882fed13
Overflow when calling Calendar.date(from:) (#690)
Validate the given `DateComponents` values up front to align with the supported Calendar calculation date range, defined as `Date.validCalendarRange`.

We could alternatively guard all arithmetic operations with `...reportingOverflow`, but there are too many operations, and so it seems untenable. I opted for a more realistic approach instead. `_CalendarICU` unconditionally truncates values to `Int32`, so the results for `Calendar.date(from:)` have always been incorrect for distant dates anyways.

Fixed 129782208
2024-06-20 09:31:04 -07:00
Charles Hu
8976fc4fd6
Introduce Cmake support for SwiftFoundation (#573) 2024-06-16 22:21:28 -07:00
Tony Parker
caa08cf226
Enable complete concurrency checking in Foundation 2024-06-04 10:41:59 -07:00
Charles Hu
6566925d60
Update remaining references of FoundationICU to _FoundationICU (#649) 2024-06-03 14:59:28 -07:00
Hristo Staykov
12a48a2448
Implement Calendar.RecurrenceRule.recurrences(of:in:) (#464)
This commit implements  `Calendar.RecurrenceRule.recurrences(of:in:)` as pitched
in #422.

This type models a subset of RRULE as specified in RFC-5545, section 3.3.10. One
notable difference is that it doesn't support a frequency of "secondly", as that
was not part of the original proposal. It also implements RFC-7529 Non-Gregorian
Recurrence Rules and works with any instance of `Calendar`.

Recurrences are calculated according to our interpretation of the RFCs. As such,
the resulting dates may differ in certain edge cases when compared to other open
source implementations.
2024-05-01 12:19:59 -07:00
Takumi Muraishi
60691c5699
(127126788) Fix some typos (#552)
* fix typos

* fix typo minimum

* fix typos

* fix typos in test
2024-04-26 13:28:03 -07:00
Tina Liu
657dc816df
Add components in the order of granularity in date(byAdding:to:) (#482)
* Add components in the order of granularity in `date(byAdding:to:)`

We compute the differences in Calendar component values from the largest to the smallest in `dateComponents(_:from:to:)`, but we are not following the same order in `date(byAdding:to:)`. Change the order of the latter so we add the largest components first.

The results are the same for most cases regardless of the order. The only exception is when the addition moves the date across DST transition. The reason for this is that the implementation aims to maintain the clock time when adding units that are larger than `day` to a date, so that the time in the day remains unchanged even after time zone offset changes. However, we cannot hold this promise if the result lands in the "skipped hour" on the DST start date as that time does not actually exist. To adjust for this case, we adjust the time of the day to the correct timezone.

For example, the DST start of year 2024 in the Los Angeles time zone is 2024-03-10, where 02:00:00-0800 becomes 03:00:00-0700.

Here's what happens when we add 1 day first, then add 1 week, to 2024-03-09T02:34:36-0800, the day before DST start:

We start by adding 1 day:
2024-03-09T02:34:36-0800 + 1 day --> 2024-03-10T02:34:36-0800

This is not a valid date in this time zone, so we adjust it to -0700:
2024-03-10T02:34:36-0800 --> 2024-03-10T03:34:36-0700

Then we add a week, which is 7 days:
2024-03-10T03:34:36-0700 + 7 days -> 2024-03-17T03:34:36-0700

Notice that the local time is different in the result from that of the original, which changes from 02:34 to 03:34.

If we start by adding 1 week:
2024-03-09T02:34:36-0800 + 7 days -> 2024-03-16T02:34:36-0700

Then add a day:
2024-03-16T02:34:36-0700 + 1 day -> 2024-03-17T02:34:36-0700

The local time is the same as that of the original.

We go for the latter to allow round-tripping a date to the date by adding their differences back.

Resolves 124414807

* Update test and remove unreasonable test cases

Currently there are tests to verify the behavior of adding `DateComponents` that sets both `weekOfYear` and `weekOfMonth`. This configuration is ambiguous, and even more so when `wrapping` is `true` since the results vary depending on which component is added first.

Replace tests asserting the behavior of this unreasonable `DateComponents` with those that only uses one kind of `week` component.

* Review feedback

* Address review feedback

* Review feedback: add back a test case with updated expectation and change the test format
2024-04-17 09:42:48 -07:00
Jeremy Schonfeld
ad1c3fc865
(123127047) Remove _foundation_essentials_feature_enabled
Co-authored-by: Tony Parker <anthony.parker@apple.com>
2024-04-09 16:06:05 -07:00
Tony Parker
d65c11fead
Enable ISO8601 encoding and decoding on top of new ISO8601 implementation (#526) 2024-04-05 10:52:34 -07:00
Saleem Abdulrasool
9491cce69c
FoundationEssentials: add some missing imports for Windows (#520)
This allows us to get further into building FoundationEssentials once
again on Windows. Much of the file system work has resulted in this
module no longer being viable on Windows and will need to be replaced to
allow building on Windows which does not have the `fts` APIs.
2024-03-29 14:19:23 -07:00
Tony Parker
ec730c21f0
Build swift-corelibs-foundation as a package on top of swift-foundation (#514)
* Provide public access for some internal functions, to enable swift-corelibs-foundation

* Add access to TimeZone internals for swift-corelibs-foundation

* Fix default TimeZone for Linux

* Remove unneeded private entry point

* Do not use a recursive definition of description for String.Encoding

* Merge in some WASI changes and other Data fixes

* Add temporary initializer to the stub URL

* Remove Hashable conformance for CocoaError. This allows userInfo to be Any instead of AnyHashable

* Remove some protocols which depend on NSError from swift-foundation -- they will live in swift-corelibs-foundation

* Adjust the debug description of the GMT ICU calendar to be a little less implementation-specific

* Use an English-only description for string encodings, for compatibility with existing SCL-F clients

* Use a more compatible definition of a backstop value for Bundle
2024-03-28 14:55:31 -07:00
Tina Liu
00cc19aeaa
[Gregorian Calendar] Correctly handle last week of year and first week of year when calculating a Date from DateComponents (#494)
When deciding the component values when calculating `Date` given a `DateComponent`, we incorrectly rewind to the previous year if `weekOfYear == 1` regardless of the passed-in `month`. This adjustment is incorrect and unncessary when `month == 1` -- being in the first month already presumes the start of the year, so doing so results in over-adjustment.

Fix this by skipping this adjustment if we're already in the first month.

Resolves 124661497
2024-03-28 09:24:44 -07:00
Tina Liu
01fd2260f7
Calendar.dateComponents(:) performance issues (#512)
CalendarGregorian currently decomposes `Locale` into its identifer plus preferences, stores the two properties separately, and recreates everytime a `Locale` when needed. This results in us always creating new locales, and calling ICU whenever requesting its properties. While we do have cache in place for `Locale.init(identifier:preferences:)` for nil `preferences`, we are not hitting the cache because `preferences` is always non-nil when calendar is `.current`.

Fix this by storing a `Locale` inside calendar so we always hit the cache. This also allows `Locale.autoupdatingCurrent` to work properly -- previously you would not get the right locale back if you set `calendar.locale = Locale.autoupdatingCurrent`. This change fixes that as the identity of the `Locale` is now preserved.

Resolves 125169335
2024-03-27 10:52:19 -07:00
Hristo Staykov
cc3a63a8a6
Add Calendar.RecurrenceRule (#510)
This commit adds the new `Calendar.RecurrenceRule` struct that was introduced in
SF-0009. It doesn't implement enumeration of recurrences, that will be done in a
separate commit. Resolves rdar://120559017.
2024-03-26 13:46:23 -07:00
Tina Liu
a04d992f9b
Return early if the component value being added is zero (#480)
When adding month or year to a `Date`, we convert a `Date` to a `DateComponent`, modify the component, and convert the modified `DateComponent` back to `Date`. However for dates falling into the "repeated" time frame on DST end date, we do have have the information of which time the `DateComponent` represents when converting it back to `Date`.

This has been the design, and we have always assumed the second occurrence of the same time. The only implementation difference is that in the ICU implementation, we return early when the value is 0 and do not proceed onto adding. We should do that for GregorianCalendar too.

Resolves 124231654
2024-03-15 11:44:59 -07:00
Tina Liu
ba282e42f5
Calendar should return the first day of week of its locale (#462)
"First day of week" and "minimum days in first week" are locale specific. Move the logic of fetching the locale's preferred value into `LocaleProtocol`, so that calendar can return the value from its enclosed locale.

Resolves 123630636
2024-03-06 16:47:33 -08:00
Jeremy Schonfeld
e5211f2926
(122981400) Standardize on using internal import 2024-03-06 13:42:02 -08:00
Hristo Staykov
d32b4684ba
Calendar.date(_: , matchesComponents: ) does not check for leap months correctly (#395)
When checking if a date matches components, we were checking whether isLeapMonth
has been set, but were not reading its actual value. This meant that this method
would sometimes return wrong results in calendars that have leap months.
2024-03-01 10:22:28 -08:00
Tina Liu
ea79e273bb
[Gregorian Calendar] Guard against julian dates that are too far away to be representable by Int (#442)
We triggered a Swift runtime error when converting a `Double` to an `Int` because the value exceeds the value representable by an `Int`.
This patch works-around this issue with the following:
- Return a capped value if the date exceeds the bound before conversion.
- Ensure compatibility among various `_CalendarProtocol` observers by capping the input date upfront.

Resolves 123664232
2024-03-01 10:02:19 -08:00
Tina Liu
34abc47bd2
[Gregorian Calendar] Guard against potential infinite loop caused by iterative search (#440)
Guard against infinite loop by validating each intermittent result. This is similar to what we're doing in Calendar enumeration functions.

Resolves 123660148
2024-02-29 10:14:12 -08:00
Tina Liu
466549386b
Use _CalendarGregorian as the backing calendar for struct Calendar (#430)
- Fix precision issues around nanoseconds calculation.

Update test expectations.

- Lessen the chance of overflowing `func add(:)` by using `Double`

We eventually convert to Double before return anyways.

- Disable TestDateComponentsDiscreteConformance.testRandomSamples temporarily for 32-bit platforms

This test triggers code path that has wrong assumption on Calendar API's return value, and overflows when the input dates are distant from each other. Disable it for now. Will track the fix in 123262305

Resolves 121677598
2024-02-28 11:12:37 -08:00
Tina Liu
bcc44f2520
CalendarGregorian search functions may loop indefinitely when reaching the capped date (#423)
* CalendarGregorian search functions may loop indefinitely when reaching the capped date

We are capping the input `Date` to the internal upper bound in various internal functions. This caused the incremental search functions to loop indefinitely because the search results are always the same since the effective input never changes.

Remove the capping from internal functions entirely. The capping was added to improving performance when calling into ICU. We should instead move the capping up to Calendar.swift, the call site to reach consistent behavior, but not inside the implementation.

Also fix miscellaneous other problems found in testing

Resolves 122946218

* enable compatibility tests for CI to run

* Address review feedback

* Remove incorrect assumption -- we should not store locale's prefs as the calendar's custom first day because it may be copied accidentally
2024-02-20 09:10:27 -08:00