Dates and Times
Cocoa's time libraries have some serious problems. To begin with, several components have names that don't accurately describe what they do. NSDate holds timestamps, not dates. NSDateComponents holds date information, but also time information. It's unnecessarily cumbersome to get local date information, requiring multiple statements and the creation of multiple intermediary objects. It has no proper semantic representation of time intervals; the NSTimeInterval holds everything in seconds, which makes it impossible to represent a time like "one month" and have it increment dates with the proper local rules. To solve these problems, Tailor has its own date and time library.
The core type in Tailor's time library is a Timestamp.
This type represents a moment in time. It provides two equivalent
representations of the moment in time. The absolute representation, called
epochSeconds, is a floating-point number giving the number of seconds since
1970-01-01 00:00:00 UTC. The local representation gives the year, month,
day, hour, minute, second, and nanosecond, in a given time zone and calendar
system. Every timestamp has both representations, which means every time zone
must have a calendar and time zone. These details default to the system calendar
and time zone. You can create a time zone by providing either the absolute
representation or the local representation.
Timestamp type also provides quick methods for changing components of the
inCalendar methods convert the timestamp into a
different time zone or calendar system. The absolute representation will remain
the same, but the local representation will be recalculated with the new time
zone and calendar.
There is also a
change method which produces a new timestamp with some of the
parts of the local representation changed. For instance, if you have a
timestamp for 2015-08-21 11:48:00 UTC, and you call
timestamp.change(month: 7, day: 19), it will produce a timestamp for
2015-07-19 11:48:00 UTC. Any values you don't specify in the call to
will be left as they are.
Tailor also provides a TimeInterval type for describing a range of time. It has fields for all of the local time components: years, months, days, hours, minutes, seconds, nanoseconds. You can add time intervals to timestamps to get new timestamps; it will change the local representation by the amounts in the time interval and recompute the absolute timestamp. You can also have values in time intervals that exceed the normal bounds for that local value, so a time interval of 48 hours is equivalent to a time interval of two days.
There are shorthands for getting time intervals for simple values: the
type has methods called
days, and so on that create a time
interval with that number of years, months, or days. You can also add intervals
together, so you can have expressions like
2.hours + 30.minutes that will
create a time interval of two hours and thirty minutes. There are also
shorthands on time intervals for adding a time interval to the current time:
2.hours.fromNow gets a timestamp two hours in the future, whereas
2.hours.ago gets a timestamp two hours in the past.
Dates and Times
If you want to model a field that only has some of the local time components,
you can use the Date and
Time types. The
Date type has a year, month, day,
and calendar. It also has helper methods
getting the first and last timestamp in that date. There is also a shorthand
Date.today() for getting the current date. The
Time type has an hour,
minute, second, nanosecond, and time zone.
You can format time with a TimeFormat. A time
format specifies a way of turning a timestamp into a string, or getting a
timestamp from a string. It's composed of a sequence of
TimeFormatComponents, which represent
a single part of the time format, like a year, an hour, a time zone, or a
string literal. The time format components also have formatting options, like
whether to pad with zeros or to use an abbreviated name. You should check out
TimeFormatComponent documentation to see all of the available options.
You can create a
TimeFormat by providing the time format components in a list,
or strings for the string literal components. For instance, to format a
timestamp in ISO 8601 format, you would create a time format like this:
TimeFormat(.Year, "-", .Month, "-", .Day, " ", .Hour, ":", .Minute, ":", .Second, " ", .TimeZone).
There are also some built-in time formats that you can access as static fields
TimeFormat type, which you can see in
the documentation. Those built-in formats
also provide interesting examples of the different options for creating time
To format a timestamp with a timestamp, you can either call
timestamp.format(timeFormat). If you
want to create a timestamp from a formatted string, you can call
timeFormat.parseTime(string). If the string is not properly formatted for the
given format, this will return nil.