holsee / timex

A complete date/time library for Elixir projects.

Home Page:https://hexdocs.pm/timex

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Timex

Master Hex.pm Version InchCI Coverage Status

Timex is a rich, comprehensive Date/Time library for Elixir projects, with full timezone support via the :tzdata package. If you need to manipulate dates, times, datetimes, timestamps, etc., then Timex is for you! It is very easy to use Timex types in place of default Erlang types, as well as Ecto types via the timex_ecto package.

The complete documentation for Timex is located here.

Migrating to Timex 2.x

See the Migrating section further down for details.

Getting Started

There are some brief examples on usage below, but I highly recommend you review the API docs here, there are many examples, and some extra pages with richer documentation on specific subjects such as custom formatters/parsers, etc.

Adding Timex To Your Project

To use Timex with your projects, edit your mix.exs file and add it as a dependency:

defp deps do
  [{:timex, "~> x.x.x"}]
end

defp application do
  [applications: [:timex]]
end

Quickfast introduction

To use Timex, I recommend you add use Timex to the top of the module where you will be working with Timex modules, all it does is alias common types so you can work with them more comfortably. If you want to see the specific aliases added, check the top of the Timex module, in the __using__/1 macro definition.

Here's a few simple examples:

> use Timex
> date = Date.today
%Date{year: 2016, month: 2, day: 29}

> datetime = DateTime.today
%DateTime{year: 2016, month: 2, day: 29,
          hour: 12, minute: 30, second: 30, millisecond: 120, timezone: %TimezoneInfo{...}}

> timestamp = Time.now
{1457, 137754, 906908}

> default_str = Timex.format(datetime, "{ISO:Extended}")
{:ok, "2016-02-29T12:30:30.120+00:00"}

> strftime_str = Timex.format(datetime, "%FT%T%:z", :strftime)
{:ok, "2016-02-29T12:30:30+00:00"}

> Timex.parse(default_str, "{ISO:Extended}")
{:ok, %DateTime{...}}

> Timex.parse(strftime_str, "%FT%T%:z", :strftime)
{:ok, %DateTime{...}}

> Time.diff(Time.now, Time.zero, :days)
16850

> Timex.shift(date, days: 3)
%Date{year: 2016, month: 3, day: 3}

> Timex.shift(date, hours: 2, minutes: 13)
%DateTime{year: 2016, month: 2, day: 29,
          hour: 14, minute: 43, second: 30, millisecond: 120, timezone: %TimezoneInfo{...}}

> timezone = Timex.timezone("America/Chicago", DateTime.today)
%Timex.TimezoneInfo{abbreviation: "CST",
 from: {:sunday, {{2015, 11, 1}, {1, 0, 0}}}, full_name: "America/Chicago",
 offset_std: 0, offset_utc: -360, until: {:sunday, {{2016, 3, 13}, {2, 0, 0}}}}

> Timezone.convert(datetime, timezone)
%DateTime{year: 2016, month: 2, day: 29,
          hour: 6, minute: 30, second: 30, millisecond: 120,
          timezone: %TimezoneInfo{abbreviation: "CST", ...}}

> Timex.equal?(Date.today, DateTime.today)
true

> Timex.before?(Date.today, Timex.shift(Date.today, days: 1))
true

There are a ton of other functions for Dates, Times, and DateTimes, way more than can be covered here. Hopefully the above gives you a taste of what the API is like!

Extensibility

Timex exposes a number of extension points for you, in order to accomodate different use cases:

You can use custom Date/DateTime types with Timex via the Timex.Convertable protocol, which gives you a way to convert your type to various Timex types, and then use the Timex API to manipulate them, for example, you could use the Calendar library's types with Timex via Comparable, or Ecto's, or your own!

You can compare/diff custom Date/DateTime types with Timex via the Timex.Comparable protocol, which also understands types which implement Timex.Convertable, allowing you to use Comparable as soon as you've implemented Convertable!

The same is true for Timex's API in general - if you pass a type which implements Timex.Convertable, and the type is not a native Timex one, it will be coerced to one via that protocol.

You can provide your own formatter/parser for Date/DateTime strings by implementing the Timex.Format.DateTime.Formatter and/or Timex.Parse.DateTime.Parser behaviours, depending on your needs.

Common Issues

Warning: Timex functions of the form iso_* behave based on how the ISO calendar represents dates/times and not the ISO8601 date format. This confusion has occured before, and it's important to note this!

  • If you need to use Timex from within an escript, add {:tzdata, "~> 0.1.8", override: true} to your deps, more recent versions of :tzdata are unable to work in an escript because of the need to load ETS table files from priv, and due to the way ETS loads these files, it's not possible to do so.

Migrating

If you have been using Timex pre-2.x, and you are looking to migrate, it's fairly painless, but important to review the list of breaking changes and new features.

Overview of 2.x changes

Please see the CHANGELOG.md file for the list of all changes made, below are a brief recap of the major points, and instructions on how to migrate your existing Timex-based code to 2.x. I promise it's easy!

  • There are now three date types: Date, DateTime, and AmbiguousDateTime. The first two are pretty obvious, but to recap:
    • If you are working with dates and don't care about time information - use Date
    • For everything else, use DateTime
    • AmbiguousDateTime is returned in cases where timezone information is ambiguous for a given point in time. The struct has two fields before and after, containing DateTime structs to choose from, based on what your intent is. It is up to you to choose one, or raise an error if you aren't sure what do to.
  • To accompany AmbiguousDateTime there is also AmbiguousTimezoneInfo, which is almost the same thing, except it's fields contain TimezoneInfo structs to choose from. This one is used mostly internally, but if you use Timezone.get, you'll need to plan for this.
  • All functions which are not specific to a given date type, are now found under the Timex module itself, all functions which are shared or common between Date and DateTime can also be found under Timex and it will delegate to the appropriate module, this should make it easier to use Date and DateTime together without having to remember which API to call for a specific value, Timex will just do the right thing for you.
  • Timex.Date and Timex.DateTime expose APIs specific to those types, Timex.DateTime is effectively the older API you are familiar with from pre-2.x Timex. Timex.Date is no longer the main API module, use Timex
  • Date/DateTime formatting and parsing APIs are exposed via the Timex module, but the old formatter and parser modules are still there, the exception being DateFormat, which has been removed, if you were using it, change to Timex.
  • Date/DateTime/Erlang datetime tuple/etc. common conversions are now exposed via the Timex.Convertable protocol. Implementations for those types are already included. Timex.Date.Convert is removed, as well as the DateConvert alias, use Timex.Convertable instead

There was a significant amount of general project improvements done as part of this release as well:

  • Shifting dates/times is now far more accurate, and more flexible than it was previously, shifting across leaps, timezone changes, and non-existent time periods are now all fully supported
  • The API does a much better job of validation and is strict about inputs, and because all APIs now return error tuples instead of raising exceptions, it is much easier to handle gracefully.
  • The code has been reorganized into a more intuitive structure
  • Fixed typespecs, docs, and tests across the board
  • Almost 100 more tests, with more to come
  • Cleaned up dirty code along the way (things like single-piping, inconsistent parens, etc.)

Migration steps (1.x -> 2.x)

Depending on how heavily you are using the various features of Timex's API, the migration can be anywhere from 15 minutes to a couple of hours, but the steps below are a guide which should help the process go smoothly. For the vast majority of folks, I anticipate that it will be a very small time investment.

  1. Change all Timex.Date references to Timex, except those which are creating DateTime values, such as Date.now, those references should be changed to point to DateTime now.
  2. Change all DateFormat references to Timex, DateFormat was removed.
  3. Change all Timex.Date.Convert or DateConvert references to Timex or Timex.Convertable, the former have become the latter
  4. Make sure you upgrade timex_ecto as well if you are using it with your project
  5. Compile, if you get warnings about missing methods on Timex, they are type-specific functions for DateTime, so change those references to Timex.DateTime
  6. You'll need to modify your code to handle error tuples instead of exceptions
  7. You'll need to handle the new AmbiguousDateTime and AmbiguousTimezoneInfo structs, the best approach is to pattern match on API return values, use DateTime if it was given, or select :before or :after values from the Ambiguous* structs. Your code will become a lot safer as a result of this change!
  8. Unit names are soft-deprecated for now, but you'll want to change references to abbreviated units like secs to their full names (i.e. seconds) in order to make the stderr warnings go away.

And that's it! If you have any issues migrating, please ping me, and I'll be glad to help. If you have a dependency that uses Timex which you'd like to get updated to 2.x, open an issue here, and I'll submit a PR to those projects to help bring them up to speed quicker.

Roadmap

The following are an unordered list of things I plan for Timex in the future, if you have specific requests, please open an issue with "RFC" in the title, and we can discuss it, and hopefully get input from the community.

  • 100% test coverage (well under way!)
  • QuickCheck tests (haven't started this, but I really want to start ASAP)
  • Locale-aware formatting/parsing (a relatively high priority)
  • {ASP.NET} formatting/parsing token for interop with .NET services (probably in the next release)
  • Relative time formatter/parser, along the lines of Moment.js's fromNow, toNow, timeTo, and timeFrom formatting functions.
  • Calendar time formatter/parser, along the lines of Moment.js's calendar time formatter
  • Richer duration support via the Interval module
  • Recurring dates/times API
  • Support for calendars other than Gregorian (e.g. Julian)

License

This software is licensed under the MIT license.

About

A complete date/time library for Elixir projects.

https://hexdocs.pm/timex

License:MIT License


Languages

Language:Elixir 100.0%