Hi Pitiphong,
Thanks for taking the time and energy to pitch this, too! If we can find
a good solution for matching this up with ISO 8601, and we have high
demand for this feature, I think it will be worth reconsidering again in
the future.
Thanks for the input!
— Itai
On 8 Sep 2017, at 13:00, Pitiphong Phongpattranont wrote:
Hi Itai,
As I told you in my last email that I’m thinking about the ISO 8601
case. After thinking about that, having a discussion in the Swift
Evolution and reading your emails, I think it may not worth to add
this into Swift Standard Library. I think the use case is not that
much so it’s not worth the cost of maintenance alone not to mention
or think about how to implement it properly (if we choose to do and
support the `iso8601` strategy.
I think I will close this pitch and would like to thank you for
reviewing and discussing on this.
— Pitiphong P.
On 7 Sep BE 2560, at 01:03, Itai Ferber <ifer...@apple.com> wrote:
Hi Pitiphong,
Don’t worry — your original email was clear, and we are on the
same page about Date{En,De}codingStrategy and
DateComponents{En,De}codingStrategy being separate things.
To clarify my points, though, there are two main things I want to
say:
I think there is a mismatch here between your goal of representing
the components of a date (and what DateComponents can specifically
hold) and the goal of ISO 8601
I think that there is an inherent problem in parsing DateComponents
due to ambiguity
I think both of these issues can be solved by reading and writing a
Date (formatted however you need it to be) instead of DateComponents.
To elaborate:
DateComponents is meant to be a container for an arbitrary subset of
information about a Date. A Date represents a specific instant in
time, but DateComponents are effectively meaningless without
additional context. In the examples that you give, it’s possible to
represent the concepts at hand with DateComponents, but in order to
make those components actionable and meaningful, you still need to
convert them to Dates. Note also that:
It’s entirely possible to create a DateComponents which represents
a date which does not exist, or a time which does not exist
Any of these concepts can also be represented by a Date instead of
just components; e.g., an all-day event can be represented by a Date
that represents the beginning of the day (00:00:00) and a flag that
indicates that the time of the event can be ignored, or by a start
Date that represents the start of the day and and end Date that
represents the end of the day
Unlike DateComponents, ISO 8601 strings have some structure to them.
They cannot represent just a time zone, for instance, or some
singular components of a date/time (e.g. a month without a year, a
day without a month and year, a minute without an hour, a second
without a minute and hour, etc.). I think this is a relatively large
conceptual mismatch that is worth considering deeply. There are a lot
of DateComponents instances which simply cannot be represented by an
ISO 8601 string
There is also the issue of decoding arbitrary ISO 8601 strings into
DateComponents. DateComponents, having no structure at all, have no
specified format they can expect to decode from, and ISO 8601 does
not always provide that structure. Consider the following example:
ISO 8601 allows for date representations by year, month, and day
(YYYY-MM-DD), among other forms. But it also allows days to be left
unspecified (YYYY-MM), and even months (YYYY)
Similarly, it allows for a time representations by hour, minute, and
second (hh:mm:ss), but also just hour and minute (hh:mm), and just
hour (hh). Importantly, it allows time separators to be omitted
(hhmmss, hhmm, hh)
Consider then, attempting to parse the string "2017" without any
context — what DateComponents should be read out? Intuitively, 2017
looks like a year (YYYY), but it is equally valid to parse as the
time 20:17 (hhmm). Without knowing the expected format, parsing is
ambiguous
We cannot promise to parse DateComponents in all cases because there
are many combinations of strings that are just completely ambiguous.
So, to get at the core of this — if there is a specific format that
you would like to encode to and from, why not do so with a Date and a
DateFormatter (or if you need ISO 8601 specifically,
ISO8601DateFormatter)? With a formatter, the format is unambiguous
because you explicitly provide it, and there is nothing the date
can’t represent that DateComponents can. You can always parse the
date and pull out only those components that you care about. You also
mention interoperability with an external JSON source — how is that
source producing a string/parsing one back? [What I’m getting at
here is: what is the value of adding a new, potentially risky
strategy over existing methods that might work just as well, or
better?]
And lastly, if .iso8601 is not necessarily a good fit for this
strategy, what separates .custom from just overriding encode(to:) and
init(from:) and writing the components out in the format that you
need?
I think answers to these questions can help us push this forward. :)
— Itai
On 5 Sep 2017, at 10:41, Pitiphong Phongpattranont wrote:
Hi Itai,
I think my first pitch email was not clear enough and want to sorry
for that. I have been working on a calendar app for awhile and
understand the concept of calendar or date and time programming in
some level. I didn’t pitch the idea of encoding and decoding `Date`
value with this `DateComponents{Encoding/Decoding}Strategy`. I still
agree that `Date` value should be encoded/decoded with the
`Date{Encoding/Decoding}Strategy`. The
DateComponents{Encoding/Decoding}Strategy I pitched only apply for
`DateComponents` value only.
About the use case, I think there are some application which store an
information of a `Date` value that is not include a time value (A
date of September 6th, 2017) for example a calendar app which want to
store the Start and End date of an `All Day Event` with a value of
DateComponents type or an alarm app which want to store just a time
of the day that user want to set an recurring alarm (10:30am.)
The problem I found with the current implementation is that I have no
control on how the DateComponents implement the conformance methods
of the Encodable and Decodable protocol. This means that if I have a
service that serialize those properties with a difference notation
(ISO 8601 in my case) then I cannot rely on the auto synthesized
implementation from the compiler and need to do a manual
encoding/decoding by manually implement the Encodable and Decodable
Lastly, on the issue that `ISO8601` standard does not support every
components in DateComponents, I still haven’t thought this though
and still thinking about it. I want to pitch the idea first and would
like to have a discussion/brainstorm on should we do this and how we
can do it. My backup plan is doesn’t include the `iso8601` strategy
but still have the `custom` strategy for those who need to apply a
custom encoding/decoding strategy which will be apply to all values
in a payload. Since we encode/decode a JSON from one source at a time
and the encoding/decoding strategy of DateComponents of that source
should be consistency throughout its types (which may be the types
that I own or the types from a 3rd party service), I think this still
is a valid use case for providing a custom strategy.
Thank you
— Pitiphong P.
On 6 Sep BE 2560, at 00:15, Itai Ferber <ifer...@apple.com
<mailto:ifer...@apple.com>> wrote:
Hi Pitiphong,
Thanks for pitching this! My main question here is about the use
case. Since encoding/decoding strategies apply to all values in a
payload (whether or not those belong to types that you own), they
inherently come with some risk.
What is the use case in mind for needing to encode and decode
DateComponents directly, as opposed to encoding and decoding a Date
instance and pulling the components you need from that?
From a correctness standpoint, I also want to point out that
DateComponents is really just a "bag of stuff" that doesn’t
necessarily mean much until converted into a Date through a Calendar
and a TimeZone. There is somewhat of a mismatch between this "bag of
stuff" and what ISO 8601 intends to represent — an actual date and
time. It’s possible to represent things in a DateComponents that
don’t really make sense for (or are not supported by)
ISO-8601-formatted dates. For instance, you can have a
DateComponents which just has a TimeZone, but ISO 8601 does not
allow representing a time zone without a corresponding time.
DateComponents also, for instance, has a quarter component (among
others) which I’m almost certain ISO 8601 has no equivalent for.
Given that conceptual mismatch, I think we’d need a very
compelling use case to support this over simply using Date.
— Itai
On 3 Sep 2017, at 0:55, Pitiphong Phongpattranont via
swift-evolution wrote:
Hi folks, I have an idea on improving the JSON{Encoder/Decoder} to
pitch.
Since JSON doesn’t have a native representation for
`DateComponents` like it doesn’t have for `Date` too so that
there’re many ways to represent it in JSON, for example ISO 8601,
UNIX timestamp, etc. for Date. There are also a few ways to
represent `DateComponents` too, for example ISO 8601
(https://en.wikipedia.org/wiki/ISO_8601
<https://en.wikipedia.org/wiki/ISO_8601>) also describes how to
represent some of the valid date components (e.g. "2017-09-03”).
Unlike what JSON{Encoder/Decoder} does to represent `Date` value
with several strategy but there is no support like that for
`DateComponents`.
The current implementation DateComponents is to encode/decode with
KeyedContainer and cannot provide a custom or ISO 8601 compatible
implementation. So I think JSON{Encoder/Decoder} should have a
strategy for encoding/decoding `DateComponents` just like for Date
Here’s an initial `DateComponentsStrategy` strategy that I want
JSON{Encoder/Decoder} I can think of now, any suggestion is
welcomed.
```swift
/// The strategy to use for encoding `DateComponents` values.
public enum DateComponentsStrategy {
/// Defer to `Date` for choosing an encoding. This is the default
strategy.
case deferredToDateComponents
/// Encode the `Date` as an ISO-8601-formatted string (in RFC 3339
format).
case iso8601
/// Encode the `Date` as a custom value encoded by the given
closure.
///
/// If the closure fails to encode a value into the given encoder,
the encoder will encode an empty automatic container in its place.
case custom((DateComponents, Encoder) throws -> Void)
}
```
What do you guys think about this pitch?
Pitiphong Phongpattranont
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
<https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution