GithubHelp home page GithubHelp logo

bitwalker / timex Goto Github PK

View Code? Open in Web Editor NEW
1.7K 24.0 366.0 2.57 MB

A complete date/time library for Elixir projects.

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

License: MIT License

Elixir 100.00%
elixir datetime calendar

timex's Introduction

Timex

Master Hex.pm Version 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 3.x

If you are coming from an earlier version of Timex, it is recommended that you evaluate whether or not the functionality provided by the standard library Calendar API is sufficient for your needs, as you may be able to avoid the dependency entirely.

For those that require Timex for one reason or another, Timex now delegates to the standard library where possible, and provides backward compatibility to Elixir 1.8 for APIs which are used. This is to avoid duplicating effort, and to ease the maintenance of this library in the future. Take a look at the documentation to see what APIs are available and how to use them. Many of them may have changed, been removed/renamed, or have had their semantics improved since early versions of the library, so if you are coming from an earlier version, you will need to review how you are using various APIs. The CHANGELOG is a helpful document to sort through what has changed in general.

Timex is primarily oriented around the Olson timezone database, and so you are encouraged to use those timezones in favor of alternatives. Timex does provide compatibility with the POSIX-TZ standard, which allows specification of custom timezones, see this document for more information. Timex does not provide support for timezones which do not adhere to one of those two standards. While Timex attempted to support timezone abbreviations without context in prior versions, this was broken, and has been removed.

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.

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
> Timex.today()
~D[2016-02-29]

> datetime = Timex.now()
#<DateTime(2016-02-29T12:30:30.120+00:00Z Etc/UTC)

> Timex.now("America/Chicago")
#<DateTime(2016-02-29T06:30:30.120-06:00 America/Chicago)

> Duration.now()
#<Duration(P46Y6M24DT21H57M33.977711S)>

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

> {:ok, relative_str} = Timex.shift(datetime, minutes: -3) |> Timex.format("{relative}", :relative)
{:ok, "3 minutes ago"}

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

> Timex.parse(strftime_str, "{ISO:Extended}")
{:ok, #<DateTime(2016-02-29T12:30:30.120+00:00 Etc/Utc)}

> Timex.parse!(strftime_str, "%FT%T%:z", :strftime)
#<DateTime(2016-02-29T12:30:30.120+00:00 Etc/Utc)

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

> Timex.shift(date, days: 3)
~D[2016-03-03]

> Timex.shift(datetime, hours: 2, minutes: 13)
#<DateTime(2016-02-29T14:43:30.120Z Etc/UTC)>

> timezone = Timezone.get("America/Chicago", Timex.now())
#<TimezoneInfo(America/Chicago - CDT (-06:00:00))>

> Timezone.convert(datetime, timezone)
#<DateTime(2016-02-29T06:30:30.120-06:00 America/Chicago)>

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

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

> interval = Timex.Interval.new(from: ~D[2016-03-03], until: [days: 3])
%Timex.Interval{from: ~N[2016-03-03 00:00:00], left_open: false,
 right_open: true, step: [days: 1], until: ~N[2016-03-06 00:00:00]}

> ~D[2016-03-04] in interval
true

> ~N[2016-03-04 00:00:00] in interval
true

> ~N[2016-03-02 00:00:00] in interval
false

> Timex.Interval.overlaps?(Timex.Interval.new(from: ~D[2016-03-04], until: [days: 1]), interval)
true

> Timex.Interval.overlaps?(Timex.Interval.new(from: ~D[2016-03-07], until: [days: 1]), interval)
false

There are a ton of other functions, all of which work with Erlang datetime tuples, Date, NaiveDateTime, and DateTime. The Duration module contains functions for working with Durations, including Erlang timestamps (such as those returned from :timer.tc)

Extensibility

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

Timex itself defines its core operations on the Date, DateTime, and NaiveDateTime types using the Timex.Protocol protocol. From there, all other Timex functionality is derived. If you have custom date/datetime types you want to use with Timex, this is the protocol you would need to implement.

Timex also defines a Timex.Comparable protocol, which you can extend to add comparisons to custom date/datetime types.

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

Timex with escript

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.

If your build still throws an error after this, try removing the _build and deps folder. Then execute mix deps.unlock tzdata and mix deps.get.

Automatic time zone updates

Timex includes the Tzdata library for time zone data. Tzdata has an automatic update capability that fetches updates from IANA and which is enabled by default; if you want to disable it, check the Tzdata documentation for details.

License

This software is licensed under the MIT license.

timex's People

Contributors

alco avatar alvinlindstam avatar atabary avatar barbeque avatar bbense avatar bitwalker avatar blackbaud-tommaszk avatar byhbt avatar ckhrysze avatar fsabe avatar gabrielelana avatar gutschilla avatar iamvery avatar jadlr avatar keichan34 avatar krishandley avatar lucazulian avatar mbramson avatar mlovic avatar nathanl avatar obrok avatar petebarton avatar pragmaticivan avatar sasa1977 avatar slavakisel avatar squaini avatar tbk145 avatar tubedude avatar x4lldux avatar xavier avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

timex's Issues

No specs in time module

The date module seems to be really well speced out but I don't see any specs in the time module. Is there any reason for this or is it just something that is waiting to be done, maybe by me?

Missed braces in Timex.Timezone.Local.read_timezone_data

Missed braces at timezone_local.ex:161 causing:

iex(43)> Timex.Timezone.Local.lookup                                             
** (FunctionClauseError) no function clause matching in Enumerable.Function.reduce/3
    (elixir) lib/enum.ex:2245: Enumerable.Function.reduce(#Function<1.39496918/1 in Timex.Timezone.Local.read_timezone_data/3>, {:cont, []}, #Function<35.62937109/2 in Enum.reduce/3>)
    (elixir) lib/enum.ex:1265: Enum.reduce/3
    (elixir) lib/enum.ex:1798: Enum.to_list/1
             lib/timezone/timezone_local.ex:162: Timex.Timezone.Local.read_timezone_data/3
             lib/timezone/timezone_local.ex:71: Timex.Timezone.Local.localtz/2

wrong local date convert

iex(80)> Date.local
%Timex.DateTime{calendar: :gregorian, day: 28, hour: 16, minute: 24, month: 5,
 ms: 607, second: 11,
 timezone: %Timex.TimezoneInfo{dst_abbreviation: "CDT",
  dst_end_day: {:last, :sun, :oct}, dst_end_time: {2, 0}, dst_name: "CDT",
  dst_start_day: {1, :sun, :apr}, dst_start_time: {2, 0},
  full_name: "America/Bahia_Banderas", gmt_offset_dst: 60, gmt_offset_std: -360,
  standard_abbreviation: "CST", standard_name: "CST"}, year: 2015}
iex(81)> Date.now |> Date.local
%Timex.DateTime{calendar: :gregorian, day: 28, hour: 3, minute: 24, month: 5,
 ms: 0, second: 21,
 timezone: %Timex.TimezoneInfo{dst_abbreviation: "CDT",
  dst_end_day: {:last, :sun, :oct}, dst_end_time: {2, 0}, dst_name: "CDT",
  dst_start_day: {1, :sun, :apr}, dst_start_time: {2, 0},
  full_name: "America/Bahia_Banderas", gmt_offset_dst: 60, gmt_offset_std: -360,
  standard_abbreviation: "CST", standard_name: "CST"}, year: 2015}
iex(82)> Date.now
%Timex.DateTime{calendar: :gregorian, day: 28, hour: 8, minute: 24, month: 5,
 ms: 163, second: 31,
 timezone: %Timex.TimezoneInfo{dst_abbreviation: "UTC", dst_end_day: :undef,
  dst_end_time: {0, 0}, dst_name: "UTC", dst_start_day: :undef,
  dst_start_time: {0, 0}, full_name: "UTC", gmt_offset_dst: 0,
  gmt_offset_std: 0, standard_abbreviation: "UTC", standard_name: "UTC"}, year: 2015}

I got stuck here...

Issues finding local time zone on OSX 10.9.3

Reported by @spatrik:

When trying out timex on my mac running OS 10.9.3, with Europe/Stockholm set to local time zone, I ran into some issues trying to parse dates. I think I've managed to understand that it's something going on in the parsing of /etc/localtime. When I run mix run -e "Timex.Timezone.local" I get the stack trace

** (FunctionClauseError) no function clause matching in Timex.Timezone.Local.parse_bool/1
(timex) lib/timezone/timezone_local.ex:924: Timex.Timezone.Local.parse_bool("")
(timex) lib/timezone/timezone_local.ex:849: anonymous fn/2 in Timex.Timezone.Local.parse_tzfile/2
(elixir) lib/enum.ex:1251: anonymous fn/3 in Enum.reduce/3
(elixir) lib/range.ex:77: Enumerable.Range.reduce/6
(elixir) lib/enum.ex:1250: Enum.reduce/3
(timex) lib/timezone/timezone_local.ex:845: Timex.Timezone.Local.parse_tzfile/2
(timex) lib/timezone/timezone_local.ex:716: Timex.Timezone.Local.read_timezone_data/3
(timex) lib/timezone/timezone_local.ex:578: Timex.Timezone.Local.localtz/2

I've tried changing the timex source to read from other files in /usr/share/zoneinfo, but it all gives the same results.

Of course this also means there is a bunch of test failing on my mac. Everything works fine on my virtual linux box. I also tried copying the linux variant of Europe/Stockholm, which is parsed without issues, even on the mac.

If there is anything else you need, I'll be happy to help.

This issue is due to a bug in the tzdata parser. I'll be addressing this by the next release of timex as well.

DateFormatter: Two digit month

Would you be open to adding a MM format to the Date Formatter to print out the month as a two-digit value?

Currently these options exist:

  ### Months
  * `{M}`       - month number (1..12)
  * `{Mshort}`  - abbreviated month name (Jan..Dec, no padding)
  * `{Mfull}`   - full month name (January..December, no padding)

However, I need to have the month always take two digits. (01 instead of 1). - As you know this is quite common with formatting.

DateFormat.parse with RFC1123z problem

Erlang 17.5
Elixir 1.0.4
Timex 0.14.3

If I take example from DateFormat file for RFC 1123 format
Timex.DateFormat.parse("Tue, 05 Mar 2013 23:25:19 +0200", "{RFC1123z}") everything works fine but if I change +0200 to +0100 like Timex.DateFormat.parse("Tue, 05 Mar 2013 23:25:19 +0100", "{RFC1123z}") I got an error:

** (MatchError) no match of right hand side value: {:error, "No timezone found for: Etc/GMT-100"}
    lib/timezone/timezone.ex:147: Timex.Timezone.diff/2
    lib/date/date.ex:380: Timex.Date.to_secs/2
    lib/timezone/timezone.ex:115: Timex.Timezone.get/2
    lib/timezone/timezone.ex:136: Timex.Timezone.convert/2
    lib/parsers/dateformat/parser.ex:106: Timex.Parsers.DateFormat.Parser.do_parse/4

Relative date parser

Given a relative statement about time, parse a date/time from it. Examples:

  • "two days ago"
  • "three hours past noon on friday"
  • "7 minutes ago"
  • "3:00pm on Monday"

And the list goes on. Need to establish what valid phrases can be composed of, and write a new tokenizer for these relative date strings.

Not working in exrm release

Hi,
I'm using Timex 0.19.2 and it works as expected. But ..., it does not work inside my exrm (0.19.2) releases. All I can say right now is that no Timex modules are available when I attach to the console. Fortunately U also maintain the exrm repo.

Auto-generate TimezoneInfos from Olson tzdata

Right now, TimezoneInfos are generated from a list of tuples which were generated from this year's tzdata. This is not maintainable moving forward. My plan for fixing/improving this:

  • Write a tzdata parser for the Olson timezone database
  • Write a mix task which downloads the most current tzdata, parses it and converts to Elixir terms which are then stored in priv/tzdata/database.exs.
  • On compilation, read priv/tzdata/database.exs, and inline lookups for individual zones.
  • Reimplement Timezone modules using data from the Olson database.

This will make it so that it's trivial to keep Timex up to date with Olson db changes.

Parsing a RFC1123z date string is not properly converting the input date to UTC

The example from the Parsing Dates section in the README doesn't work as expected. See the following steps to reproduce:

klausi@devil2:~/dev/timex (master)λ iex -S mix
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> use Timex
nil
iex(2)> date  = Date.from({{2013,3,5},{23,25,19}}, "Europe/Athens")
%Timex.DateTime{calendar: :gregorian, day: 5, hour: 23, minute: 25, month: 3,
 ms: 0, second: 19,
 timezone: %Timex.TimezoneInfo{abbreviation: "EET",
  from: {:sunday, {{2012, 10, 28}, {3, 0, 0}}}, full_name: "Europe/Athens",
  offset_std: 0, offset_utc: 120, until: {:sunday, {{2013, 3, 31}, {3, 0, 0}}}},
 year: 2013}
iex(3)> {:ok, ^date} = DateFormat.parse("Tue, 05 Mar 2013 23:25:19 +0200", "{RFC1123z}")
** (MatchError) no match of right hand side value: {:ok, %Timex.DateTime{calendar: :gregorian, day: 5, hour: 23, minute: 25, month: 3, ms: 0, second: 19, timezone: %Timex.TimezoneInfo{abbreviation: "UTC", from: :min, full_name: "UTC", offset_std: 0, offset_utc: 0, until: :max}, year: 2013}}

Uniform parsing of "Z" and "+0000" timezones

Currently there seems to be no way to uniformly parse an ISO 8601 string. Additionally some valid ways of representing timezone offsets are rejected. If I understand correctly the following assertions should be true but all of them give a parse error.

date1 = Date.from({{2014, 8, 14}, {12, 34, 33}})
assert { :ok, ^date1 } = parse("2014-08-14T12:34:33Z", "{ISO}")
assert { :ok, ^date1 } = parse("2014-08-14T12:34:33+00", "{ISO}")
assert { :ok, ^date1 } = parse("2014-08-14T12:34:33+00:00", "{ISO}")

I can try my hand at fixing that if you think this is correct.

Doesn't seem to be a way to create a Date with ms or us set

I need a timestamp (ISO or ISOz) that shows fractional seconds. I can get this if I set the :ms field in the a Date after I've created it using Date.now(). I've put some code at the bottom that provides what I need.

Date.now() seems to be using :calendar.universal_time() which does not have fractional seconds. I can't find any calls to :erlang.now() in Timex.

I see that Timex.Date pretty much ignores the fractional seconds throughout (e.g. {mega, sec, _} is frequently used).

Anyway, this hack seems to work the way I want.

  def timestamp() do
    now = :erlang.now()
    {mega, sec, micro} = now
    ms = div (rem ((mega*1000000 + sec)*1000000 + micro), 1000000), 1000
    ut = Timex.Date.construct( :calendar.now_to_datetime(now), Timex.Date.timezone(:utc))
    d = %{ ut | :ms => ms }
    Timex.DateFormat.format!(d, "{ISOz}")
  end

Possible to extract an tuple with the datetime from Timex?

Is it possible given a Timex call to return the created data-time as a tuple?

e.g.

Date.from({{2015,06,12},{09:00:00}})
|> Date.as_tuple()

would export: {{2015,06,12},{09:00:00}}

(reason is I want to do more processing on the data using Timex but then get a tuple at the end)

Convert Date From Unixtime

I have epoch_time taken from RethinkDB I believe that's unixtime format, for example: 1423155600. How to convert it into Date format using Timex?

Improvements to date parsing

The current strftime parser is broken, and while the default parser is solid, it has holes in it's testing. I plan on reimplementing both parsers/formatters with the goal of making sure they both have complete test coverage, are fully spec'd and have updated docs.

One issue related to this that was reported recently was with the default parser:

"yeah, i just ran into this. Probably should guard M is not greater than 12"

DateFormat.parse("2014-31-7", "{YYYY}-{M}-{D}")             
{:ok,
 %Timex.DateTime{calendar: :gregorian, day: 7, hour: 0, minute: 0, month: 31,
  ms: 0, second: 0,
  timezone: %Timex.TimezoneInfo{dst_abbreviation: "UTC", dst_end_day: :undef,
   dst_end_time: {0, 0}, dst_name: "UTC", dst_start_day: :undef,
   dst_start_time: {0, 0}, full_name: "UTC", gmt_offset_dst: 0,
   gmt_offset_std: 0, standard_abbreviation: "UTC", standard_name: "UTC"},
  year: 2014}, ""}

Issues like these need to be addressed with tests (and obviously fixes). This is scheduled for timex's next release.

Consider making unit names more descriptive

The gist of the proposal is to rename time units used in diff(), convert(), and other functions to have more descriptive names:

usecs -> microseconds
msecs -> milliseconds
secs  -> seconds
mins  -> minutes

This will bring more consistency with the other units (hours, days, etc.). In the long term, having descriptive names trumps the convenience of having short ones because there is no one true way to shorten them (to my knowledge, at least).

Date clarity in the documentation

On the readme, Date is used in the examples. Date really is Timex.Date. There is a use Timex when explaining "Erlang datetime tuples", which explains how to get it in the proper scope. This can be confusing for newer elixir users (me).

It might be better to use the full names in the documentation (Timex.Date) to leave off any confusion for newer Elixir users.

Thoughts?

Thanks again bitwalker 😃

Confusion about ISO triplet

I found the iso_triplet functions related functions and (wrongly) assumed they were referring to {year, month, day} tuples -- after all, an ISO-8601 date is in the form YYYY-MM-DD. I see now that the ISO 8601 standard also supports a week date:

https://en.wikipedia.org/wiki/ISO_week_date

...but I had never heard about that before, and was quite confused about the iso_triplet functions when I first tried to use them. I suspect it's a common mistake others will make. What do you think about renaming the iso_triplet functions to something like iso_week_date_triplet or similar to make it clear that it's not the { year, month, date} triplets someone might expect?

Also, I see that I can construct a timex date time from a { year, month, date } triplet using Timex.Date.from but I don't see a way to convert back to that form with any of the provided functions. Am I just not seeing it or is that not part of the API provided by Timex? Would you consider adding it?

Thanks!

Date.local is around 280 times slower in version 0.14.3 and 0.16.2 compared to 0.13.5

Using the test below, mix test --trace shows Date.local is around 280 times slower in version 0.14.3 and 0.16.2 when compared to version 0.13.5

test "test date now" do
  for _ <- 1..5000, do: Date.now
end

test "test date local" do
  for _ <- 1..5000, do: Date.local
end

test "test date local iso" do
  for _ <- 1..5000, do: DateFormat.format!(Date.local, "{ISO}")
end

0.13.5

[nick@zippy timetest]$ mix test --trace

TimetestTest
  * test date local (75.6ms)
  * test date local iso (800.2ms)
  * test date now (20.3ms)


Finished in 0.9 seconds (0.09s on load, 0.8s on tests)
3 tests, 0 failures

0.14.3

[nick@zippy timetest]$ mix test --trace

TimetestTest
  * test date now (31.0ms)
  * test date local iso (21997.8ms)
  * test date local (21219.1ms)


Finished in 43.3 seconds (0.08s on load, 43.2s on tests)
3 tests, 0 failures

0.16.2

[nick@zippy timetest]$ mix test --trace

TimetestTest
  * test date now (52.7ms)
  * test date local iso (23073.4ms)
  * test date local (22049.6ms)


Finished in 45.2 seconds (0.09s on load, 45.1s on tests)
3 tests, 0 failures

Possible bug in local timezone lookups (Windows)

This is rather feature request than a bug :)

If I include this as dependency in my project under Windows Operating system I'm getting error
" Unsupported operating system!"

** (exit) an exception was raised:
** (RuntimeError) Unsupported operating system!
lib/timezone/timezone_local.ex:29: Timex.Timezone.Local.lookup/1
lib/timezone/timezone.ex:656: Timex.Timezone.local/0
lib/date/date.ex:145: Timex.Date.local/0

GMT minus sign is ignored

When I run this:

    date_gmt7 = Date.from({{2014,7,11},{8,18,51}}, "GMT-7")
    assert { :ok, ^date_gmt7 } = parse("2014-07-11T08:18:51-07:00", "{RFC3339}")

I get this

match (=) failed
     code: {:ok, ^date_gmt7} = parse("2014-07-11T08:18:51-07:00", "{RFC3339}")
     rhs:  {:ok,
            %Timex.DateTime{calendar: :gregorian, day: 11, hour: 8, minute: 18, month: 7, ms: 0, second: 51,
             timezone: %Timex.TimezoneInfo{dst_abbreviation: "GMT+7", dst_end_day: :undef, dst_end_time: {0, 0},
              dst_name: "GMT+7", dst_start_day: :undef, dst_start_time: {0, 0}, full_name: "Etc/GMT+7", gmt_offset_dst: 0,
              gmt_offset_std: 420, standard_abbreviation: "GMT+7", standard_name: "GMT+7"}, year: 2014}}

The timezone should be GMT-7.

%Timex.DateTime{calendar: :gregorian, day: 11, hour: 8, minute: 18, month: 7, ms: 0, second: 51,
            timezone: %Timex.TimezoneInfo{dst_abbreviation: "GMT-7", dst_end_day: :undef, dst_end_time: {0, 0},
             dst_name: "GMT-7", dst_start_day: :undef, dst_start_time: {0, 0}, full_name: "Etc/GMT-7", gmt_offset_dst: 0,
             gmt_offset_std: -420, standard_abbreviation: "GMT-7", standard_name: "GMT-7"}, year: 2014}

milliseconds get lost when converting date to different timezone

iex(7)> "2015-06-10T10:11:57.315+0000" |> Timex.DateFormat.parse!("{ISO}") |> Timex.DateFormat.format!("{ISO}")
"2015-06-10T10:11:57.315+0000"
iex(8)> "2015-06-10T10:11:57.315+0000" |> Timex.DateFormat.parse!("{ISO}") |> Timex.Timezone.convert(Timex.Timezone.get("UTC")) |> Timex.DateFormat.format!("{ISO}")
"2015-06-10T10:11:57.315+0000"
iex(9)> "2015-06-10T10:11:57.315+0000" |> Timex.DateFormat.parse!("{ISO}") |> Timex.Timezone.convert(Timex.Timezone.get("CET")) |> Timex.DateFormat.format!("{ISO}")
"2015-06-10T12:11:57+0200" # <------
iex(10)> "2015-06-10T10:11:57.315+0200" |> Timex.DateFormat.parse!("{ISO}") |> Timex.Timezone.convert(Timex.Timezone.get("CET")) |> Timex.DateFormat.format!("{ISO}")
"2015-06-10T10:11:57.315+0200"


iex(12)> "2015-06-10T10:11:57.315+0000" |> Timex.DateFormat.parse!("{ISO}") |> Timex.Timezone.convert(Timex.Timezone.get("CET"))
%Timex.DateTime{calendar: :gregorian, day: 10, hour: 12, minute: 11, month: 6,
 ms: 0, second: 57,
 timezone: %Timex.TimezoneInfo{dst_abbreviation: "CEST",
  dst_end_day: {:last, :sun, :oct}, dst_end_time: {3, 0}, dst_name: "CEST",
  dst_start_day: {:last, :sun, :mar}, dst_start_time: {2, 0}, full_name: "CET",
  gmt_offset_dst: 60, gmt_offset_std: 60, standard_abbreviation: "CET",
  standard_name: "CET"}, year: 2015}

Default ISOz parser does not validate delimeters

While trying to use the output of DateFormat.parse to validate some user input I noticed it accepts this

iex>Timex.DateFormat.parse "2014 09 14 15 34 45 ", "{ISOz}"    
{:ok,
 %Timex.DateTime{calendar: :gregorian, day: 14, hour: 15, minute: 34, month: 9,
  ms: 0, second: 45,
  timezone: %Timex.TimezoneInfo{dst_abbreviation: "UTC", dst_end_day: :undef,
   dst_end_time: {0, 0}, dst_name: "UTC", dst_start_day: :undef,
   dst_start_time: {0, 0}, full_name: "UTC", gmt_offset_dst: 0,
   gmt_offset_s

I was expecting a parse error since the date string does not follow the IS8601 format "2014-09-14T15:34:45Z"

Reporting in case it's a bug

Parsing date string raises an exception since 0.14.1

before 0.14.1 (including 0.14.0)

iex(1)> "2015-06-23 17:23:52.233+0000" |> Timex.DateFormat.parse!("{ISO}")
%Timex.DateTime{calendar: :gregorian, day: 23, hour: 17, minute: 23, month: 6,
 ms: 233, second: 52,
 timezone: %Timex.TimezoneInfo{dst_abbreviation: "UTC", dst_end_day: :undef,
  dst_end_time: {0, 0}, dst_name: "UTC", dst_start_day: :undef,
  dst_start_time: {0, 0}, full_name: "UTC", gmt_offset_dst: 0,
  gmt_offset_std: 0, standard_abbreviation: "UTC", standard_name: "UTC"},
 year: 2015}

since 0.14.1

iex(1)> "2015-06-23 17:23:52.233+0000" |> Timex.DateFormat.parse!("{ISO}")
[error] Error in process <0.604.0> with exit value: {badarg,[{erlang,byte_size,[[{message,<<35 bytes>>}]],[]},{'Elixir.Exception',format_banner,3,[{file,"lib/exception.ex"},{line,106}]},{'Elixir.IEx.Evaluator',print_error,3,[{file,"lib/iex/evaluator.ex"},{line,158}]},{'Elixir.IEx.Evaluator',eval...


** (EXIT from #PID<0.604.0>) an exception was raised:
    ** (ArgumentError) argument error
        :erlang.byte_size([message: "Input string does not match format!"])
        (elixir) lib/exception.ex:106: Exception.format_banner/3
        (iex) lib/iex/evaluator.ex:158: IEx.Evaluator.print_error/3
        (iex) lib/iex/evaluator.ex:95: IEx.Evaluator.eval/2
        (iex) lib/iex/evaluator.ex:29: IEx.Evaluator.loop/1
        (iex) lib/iex/evaluator.ex:19: IEx.Evaluator.start/2

We're retrieving those values from a database which can't be parsed with newer versions

Wrong timezone for Asia/Shanghai

iex> Timex.Date.universal
%Timex.DateTime{calendar: :gregorian, day: 8, hour: 3, minute: 48, month: 5,
 ms: 495, second: 6,
 timezone: %Timex.TimezoneInfo{dst_abbreviation: "UTC", dst_end_day: :undef,
  dst_end_time: {0, 0}, dst_name: "UTC", dst_start_day: :undef,
  dst_start_time: {0, 0}, full_name: "UTC", gmt_offset_dst: 0,
  gmt_offset_std: 0, standard_abbreviation: "UTC", standard_name: "UTC"},
 year: 2015}
iex> Timex.Date.local
%Timex.DateTime{calendar: :gregorian, day: 8, hour: 11, minute: 48, month: 5,
 ms: 511, second: 11,
 timezone: %Timex.TimezoneInfo{dst_abbreviation: "CDT",
  dst_end_day: {:last, :sun, :oct}, dst_end_time: {2, 0}, dst_name: "CDT",
  dst_start_day: {1, :sun, :apr}, dst_start_time: {2, 0},
  full_name: "America/Bahia_Banderas", gmt_offset_dst: 60, gmt_offset_std: -360,
  standard_abbreviation: "CST", standard_name: "CST"}, year: 2015}
iex> Timex.Date.local |> Timex.DateFormat.format!("{ISO}")
"2015-05-08T11:53:28.810-0500"

While I'm actually in Asia/Shanghai TZ (GMT +8), but the "full_name" on local timezone is "America/Bahia_Banderas".

parse timezone failed at osx yosemeti with elixir 1.0.4

While calling Date.local, an exception is raised:

** (Protocol.UndefinedError) protocol Access not implemented for %Timex.Parsers.ZoneInfo.TransitionInfo{abbrev_index: 0, abbreviation: "N/A", gmt_offset: 32400, is_dst?: true, is_std?: true, is_utc?: false, starts_at: 0}
    (elixir) lib/access.ex:1: Access.impl_for!/1
    (elixir) lib/access.ex:44: Access.get_and_update/3
    (elixir) lib/kernel.ex:1593: Kernel.put_in/3
    (elixir) lib/enum.ex:977: anonymous fn/3 in Enum.map/2
    (elixir) lib/enum.ex:1261: Enum."-reduce/3-lists^foldl/2-0-"/3
    (elixir) lib/enum.ex:977: Enum.map/2
     (timex) lib/parsers/zoneinfo/zoneinfo.ex:133: Timex.Parsers.ZoneInfo.do_parse_transition_info/3
     (timex) lib/timezone/timezone_local.ex:225: Timex.Timezone.Local.parse_tzfile/2

System timezone:

sudo systemsetup -gettimezone
Password:
Time Zone: Asia/Shanghai

DateFormat not as simple as possible

As per timex.ex

defmodule Timex do
  defmacro __using__(_) do
    quote do
      alias Timex.DateTime
      alias Timex.Date
      alias Timex.Time
      alias Timex.TimezoneInfo
      alias Timex.Timezone
      alias Timex.Format.DateTime.DateFormat
      alias Timex.Date.Convert, as: DateConvert
      alias Timex.Format.Time.TimeFormatter, as: TimeFormat
    end
  end
  @moduledoc File.read!("README.md")
end

DateFormat is only easily accessible if I do "use Timex". Would you consider moving the module to "Timex.DateFormat" to be easily accessible (and possibly delegate all the functionality wherever you want)? It used to work and was super easy.

Feature: Automatic integration with Ecto, as per calecto

I feel tied between "calendar" and "timex". I need to parse a datestring for which timex seems to have far stronger support. But I then wish to write these to a database, where the automatic integration of calendar with ecto is neat (calecto project).

Could you consider adding an equivalent to calecto (timecto...). It appears to boil down to integrating the ecto protocol?

Thanks for listening!

Timex needs to be updated to avoid deprecations in Elixir v0.15.0

The following deprecation warnings are thrown when compiling Timex into an app with 'mix reps.compile'.

➜  dmr-watch git:(master) ✗ mix deps.get
Running dependency resolution
Unlocked:   timex
Dependency resolution completed successfully
  timex: v0.10.2
* Getting timex (package)
Checking package (http://s3.hex.pm/tarballs/timex-0.10.2.tar)
Fetched package
Unpacked package tarball (/Users/glenn/.hex/packages/timex-0.10.2.tar)
➜  dmr-watch git:(master) ✗ mix deps.compile
==> idna (compile)
==> timex
warning: the dependency timex requires Elixir "~> 0.14.3" but you are running on v0.15.0
Compiled lib/date/datetime.ex
lib/formatters/default.ex:117: warning: passing a list of bitstring modifiers is deprecated, please separate them with - instead
Compiled lib/formatters/default.ex
Compiled lib/formatters/strftime.ex
Compiled lib/time/time_formatter.ex
Compiled lib/timex.ex
Compiled lib/timezone/database.ex
lib/parsers/zoneinfo.ex:78: warning: passing a list of bitstring modifiers is deprecated, please separate them with - instead
Compiled lib/time/time.ex
lib/parsers/zoneinfo.ex:93: warning: passing a list of bitstring modifiers is deprecated, please separate them with - instead
lib/parsers/zoneinfo.ex:185: warning: passing a list of bitstring modifiers is deprecated, please separate them with - instead
lib/parsers/zoneinfo.ex:186: warning: passing a list of bitstring modifiers is deprecated, please separate them with - instead
lib/parsers/zoneinfo.ex:187: warning: passing a list of bitstring modifiers is deprecated, please separate them with - instead
Compiled lib/parsers/zoneinfo.ex
Compiled lib/timezone/timezone_info.ex
Compiled lib/date/date_convert.ex
Compiled lib/timezone/timezone_dst.ex
lib/timezone/timezone_local.ex:44: warning: System.cmd/1 is deprecated, use System.cmd/3 instead
Compiled lib/timezone/timezone_local.ex
Compiled lib/date/date.ex
Compiled lib/timezone/timezone.ex
lib/date/dateformat.ex:558: warning: passing a list of bitstring modifiers is deprecated, please separate them with - instead
lib/date/dateformat.ex:561: warning: passing a list of bitstring modifiers is deprecated, please separate them with - instead
lib/date/dateformat.ex:566: warning: passing a list of bitstring modifiers is deprecated, please separate them with - instead
Compiled lib/date/dateformat.ex
Generated timex.app

segfault when 3rd param is missing when using Task.async

I get a segfault when I forgot to include the 3rd parameter (:strftime) of DateFormat.format!

defmodule Mix.Tasks.Segfault do
  use Mix.Task
  use Timex

  def run(_args) do
    task = Task.async(fn ->
      Date.from({{2015,1,1},{1,1,1}}) |> DateFormat.format! "%Y-%m-%d" #, :strftime
    end)
    Task.await task, :infinity
  end
end
{"init terminating in do_boot",{badarg,[{erlang,byte_size,[[{message,<<59 bytes>>}]],[]},{'Elixir.Exception',format_banner,3,[{file,"lib/exception.ex"},{line,106}]},{'Elixir.Exception',format_exit,2,[{file,"lib/exception.ex"},{line,171}]},{'Elixir.Exception',format_banner,3,[{file,"lib/exception.ex"},{line,118}]},{'Elixir.Kernel.CLI',print_error,3,[{file,"lib/kernel/cli.ex"},{line,113}]},{'Elixir.Kernel.CLI',exec_fun,2,[{file,"lib/kernel/cli.ex"},{line,97}]},{'Elixir.Kernel.CLI',run,2,[{file,"lib/kernel/cli.ex"},{line,37}]},{init,start_it,1,[]}]}}
Abort trap: 6

On IRC, @ericmj says timex should unwrap [message: message] here: https://github.com/bitwalker/timex/blob/master/lib/dateformat/format_error.ex#L9

Elixir 1.0.3
Erlang/OTP 17 [erts-6.3.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Parsing of second fractions

ISO8601 allows for sub-second time amounts to appear after seconds, but trying to parse such a string results in an error:

iex(3)> DateFormat.parse("2015-07-07T06:32:38.197894Z", "{ISO}")
{:error, "Input string does not match format!"}

Edit: this only happens when there's more than 3 digits in the sub-second part.

API Review

Timex has undergone a great deal of change over the past few months. Before we can start thinking about the possibility of merging it into the standard library, I think it's important to take a step back and think about the API, and make sure it meets the following requirements:

  • User guide/intro documentation
  • Fully documented (@moduledoc, @doc, @spec)
  • Fully tested (a good suite of tests for each API function)
  • Consistency (is there uniformity to the order of arguments, can pipelines be used when chaining date/time manipulations together, is naming consistent, are modules namespaced consistently, etc).
  • Dialyzer gods are pleased.

These are all "ideal" items to be checked off before a potential merge into the standard library can be considered. These aren't strictly tasks, so much as they are a confirmation that these items have been reviewed, and are deemed satisfactory.

Error in Timex.Utils.available_modules when used via escript

When I call ...

DateFormat.format!(Date.local, "%a, %d %m %Y %T %Z", :strftime)

... from IEx, it works just fine. When I build an escript, the same code throws ...

** (UndefinedFunctionError) undefined function: Mix.Project.build_path/0
    Mix.Project.build_path()
    lib/utils/utils.ex:40: Timex.Utils.available_modules/0
    lib/utils/utils.ex:22: Timex.Utils.get_plugins/1
    lib/dateformat/formatter.ex:54: Timex.DateFormat.Formatters.Formatter.format/3
    lib/dateformat/formatter.ex:38: Timex.DateFormat.Formatters.Formatter.format!/3

... is that a bug?

Possible bug with time zone conversion wrt daylight savings

I'm working on an application that needs to be able to convert epoch timestamps to dates in a standardized system time, which is US Central (don't ask... :rage1:).

On one of the remote boxes, using Ruby's Time.at, which I have used extensively and have no reason not to trust:

[3] pry(main)> t = Time.at(1394344799)
=> 2014-03-08 23:59:59 -0600
[4] pry(main)> Time.now
=> 2015-07-18 11:48:32 -0500

Note the difference from now and the date in question - one is daylight savings and one is not.

On my local box, which is in US Eastern, I can get the right answer in Ruby using active_record/time:

[16] pry(main)> require 'active_support/time'
=> true
[17] pry(main)> t = Time.at(1394344799)
=> 2014-03-09 00:59:59 -0500
[18] pry(main)> t.in_time_zone("America/Chicago")
=> Sat, 08 Mar 2014 23:59:59 CST -06:00
[19] pry(main)> t.utc
=> 2014-03-09 05:59:59 UTC

Using Timex on my local box:

iex(13)> t = Timex.Date.from(1394344799, :secs)
%Timex.DateTime{calendar: :gregorian, day: 9, hour: 5, minute: 59, month: 3,
 ms: 0, second: 59,
 timezone: %Timex.TimezoneInfo{abbreviation: "UTC", from: :min,
  full_name: "UTC", offset_std: 0, offset_utc: 0, until: :max}, year: 2014}
iex(14)> t |> Timex.Timezone.convert("America/Chicago")
%Timex.DateTime{calendar: :gregorian, day: 9, hour: 0, minute: 59, month: 3,
 ms: 0, second: 59,
 timezone: %Timex.TimezoneInfo{abbreviation: "CDT",
  from: {:sunday, {{2014, 3, 9}, {2, 0, 0}}}, full_name: "America/Chicago",
  offset_std: 60, offset_utc: -360,
  until: {:sunday, {{2014, 11, 2}, {1, 0, 0}}}}, year: 2014}

I get the same result on a box in the central timezone, actually. t |> Timex.Date.local also gives the wrong answer on that box.

I say "possible bug" because maybe I'm not doing the conversion correctly? Or it's possible that the Ruby code is wrong (but I don't think so)?

Error with parse strftime

We have a JS client which sends date strings like 'Mon Jul 06 2015 00:00:00 GMT+0200 (CEST)' (date.toString())

Trying to parse it I get an error

iex(3)> date = "Mon Jul 06 2015 00:00:00 GMT+0200 (CEST)"
"Mon Jul 06 2015 00:00:00 GMT+0200 (CEST)"
iex(4)> Timex.DateFormat.parse!(date,"%a %b %d %Y %H:%M:%S %Z%z (%Z)", :strftime)
** (EXIT from #PID<0.1164.0>) an exception was raised:
    ** (ArgumentError) argument error
        :erlang.byte_size([message: "Invalid value for zoffs. Does not match specification for ~r/^[-+]\\d{2}([:]?\\d{2})?$/"])
        (elixir) lib/exception.ex:106: Exception.format_banner/3
        (iex) lib/iex/evaluator.ex:158: IEx.Evaluator.print_error/3
        (iex) lib/iex/evaluator.ex:95: IEx.Evaluator.eval/2
        (iex) lib/iex/evaluator.ex:29: IEx.Evaluator.loop/1
        (iex) lib/iex/evaluator.ex:19: IEx.Evaluator.start/2

whereas this works

iex(1)> date = "Mon Jul 06 2015 00:00:00 GMT +0200 (CEST)"
"Mon Jul 06 2015 00:00:00 GMT +0200 (CEST)"
iex(2)> Timex.DateFormat.parse!(date,"%a %b %d %Y %H:%M:%S %Z %z (%Z)", :strftime)
%Timex.DateTime{calendar: :gregorian, day: 6, hour: 0, minute: 0, month: 7, ms: 0, second: 0,
 timezone: %Timex.TimezoneInfo{abbreviation: "UTC", from: :min, full_name: "UTC", offset_std: 0, offset_utc: 0,
  until: :max}, year: 2015}

No timezone found for: EDT

When I am trying to parse date like that: "Mon, 02 Mar 2015 06:48:00 EDT" I am getting an error:

> {:ok, date} = Timex.DateFormat.parse("Mon, 02 Mar 2015 06:48:00 EDT", "{RFC1123}") 
{:ok,
 %Timex.DateTime{calendar: :gregorian, day: 2, hour: 6, minute: 48, month: 3,
  ms: 0, second: 0, timezone: {:error, "No timezone found for: EDT"},
  year: 2015}}
> Timex.Date.universal(date)
** (MatchError) no match of right hand side value: {:error, "No timezone found for: EDT"}
    lib/timezone/timezone.ex:147: Timex.Timezone.diff/2
    lib/timezone/timezone.ex:128: Timex.Timezone.convert/2

I opened an issue in Tzdata, but I am not sure if it is their issue.

ISO triplets don't roundtrip as expected

iex(1)> Timex.Date.from_iso_triplet({ 2014, 1, 1}) |> Timex.Date.iso_triplet
{2014, 1, 2}

Going from an iso triplet to a date and back to a triplet produces a different value than I started with. This is unexpected.

Date.compare/2 return value is incorrect

Hi!

I was scratching my head and debugging this for a while.. almost thinking my freshly baked webapp caching is completely broken ;)

Shouldn't the return value of Date.compare/2 be the other way around?

iex(21)> d1=DateFormat.parse!("Sat, 23 Aug 2014 20:08:12 +0000", "{RFC1123z}"); :ok
:ok
iex(22)> d2=DateFormat.parse!("Sat, 23 Aug 2014 20:08:13 +0000", "{RFC1123z}"); :ok
:ok
iex(23)> Date.compare d1,d2                                                     
1
iex(24)> Date.compare d2,d1
-1

Well, when d1<d2, I'd expect compare to return -1.

This would be how every comparator I can think of does it :)

Compare (nomen omen! ;) to strcmp(3):

DESCRIPTION
       The  strcmp()  function compares the two strings s1 and s2.  It returns
       an integer less than, equal to, or greater than zero if  s1  is  found,
       respectively, to be less than, to match, or be greater than s2.

Here comes Ruby:

% irb 
>> 1<=>2
=> -1
>> 2<=>1
=> 1

IIRC Java Comparator does it the same way..

Oops? :)

Help with formatting a time stamp?

Hi,
How would I go about creating an ISOz timestamp without miliseconds from the current time? (like this: 2015-06-24T05:04:13Z).
You give this example in the readme:
> Date.local |> DateFormat.format("{ISOz}") {:ok, "2015-06-24T05:04:13.910Z"}
In your tests I saw this line which is essentially what I want, but that is given a time w/o ms.

Do I need to round or preformat Date.local first?

Hope this is clear, Thank you for any suggestions.

Week index in a month for a given date

I am working on a project, where I needed week index in the context of the month and not year. I ended up writing my own private function like below

  defp week_index_in_month(date) do
    {_, week_index_of_given_date} = Timex.Date.iso_week(date)
    {_, week_index_of_first_day_of_given_month} = Timex.Date.iso_week(%{date | day: 1})
    week_index_of_given_date - week_index_of_first_day_of_given_month
  end

are you interested in getting this into the library? If so, I can provide a PR.

seg fault

use Timex
ts = "2014-12-23T13:29:50+0000"
date = DateFormat.parse(ts,"{ISO}")
DateFormat.format!(Date.shift(date,days: 1),"{ISO}")

*** stack smashing detected ***: /usr/local/lib/erlang/erts-6.2/bin/beam terminated
Segmentation fault (core dumped)

Possible parse problem with %m :strftime

Hi, I see a possible bug in the strftime parser:

iex> DateFormat.parse("150623", "%y%m%d", :strftime)
{:error,
"Invalid numeric value 62 for month. Outside of the allowed bounds: 1..12"}

iex> DateFormat.parse("151123", "%y%m%d", :strftime)
{:ok,
%Timex.DateTime{calendar: :gregorian, day: 23, hour: 0, minute: 0, month: 11,
ms: 0, second: 0,
timezone: %Timex.TimezoneInfo{abbreviation: "UTC", from: :min,
full_name: "UTC", offset_std: 0, offset_utc: 0, until: :max}, year: 2015}}

I took a poke around the code, but I can't spot the issue? Seems like the leading 0 is getting stripped somewhere along the line, so the parser cuts an extra digit for %m

Thanks if you can take a look?

Date.local/2 does not convert the time, just the timezone

When using Date.local(date, timezone) the timezone is converted, but not the actual time, which seems rather unexpected to me.

Example:

dt_utc = Date.from({{2014, 9, 22}, {12, 0, 0}})
dt_utc.hour    #=> 12
dt_jst = Date.local(dt_utc, Date.timezone("JST"))
dt_jst.hour    #=> 12  # instead of 21

`Date.to_secs` does not take timezone into account.

Example symptom:

iex(38)> Date.convert(Date.from({2014, 11, 17}, "CST"), :secs)
1416182400                                                    
iex(39)> Date.convert(Date.from({2014, 11, 17}), :secs)       
1416182400                                                    

Current implementation of Date.to_secs (

timex/lib/date/date.ex

Lines 377 to 379 in b7b7a79

def to_secs(%DateTime{:year => y, :month => m, :day => d, :hour => h, :minute => min, :second => s}, :zero) do
:calendar.datetime_to_gregorian_seconds({{y, m, d}, {h, min, s}})
end
) is not handling timezone before sending off to Erlang.

Updated documentation

The Timex API's surface area has grown to a large enough size where the README is no longer useful. Here's my plan for fixing this:

  • Set up Timex in Read The Docs
  • Make sure all documentation in the codebase is up to date (doc attributes, type specs)
  • Create a mix task to autogenerate the RTD docs from API documentation.

This should make navigating the API a lot nicer, and a lot easier, not to mention we can be sure that it's up to date and comprehensive. This issue is required to be address before Timex 1.0 will be released.

Timezone handling broken

Just a heads up: The current way time zone handling is done, means it is impossible for time zone handling to be correct for all time zones. At best it will be correct for time zones that have not changed and in a while and only for dates that are newer than the last change.

Also for instance Morocco susspends DST in the middle of summer, which the TimezoneInfo does not seem to take into account?

It is necessary to take the previous rules into account otherwise it will not work correctly, when the rules change.

The current rules used by Timex are not up to date with the TZ database, but simply updating the data will not fix the issues.

compile failed

==> tzdata
Compiled lib/tzdata/parser_organizer.ex
Compiled lib/tzdata/release_parser.ex
Compiled lib/tzdata/util.ex
Compiled lib/tzdata/table_parser.ex
Compiled lib/tzdata/parser.ex
Compiled lib/tzdata/table_data.ex
Compiled lib/tzdata/leap_sec_parser.ex
Compiled lib/tzdata/basic_data.ex
Compiled lib/tzdata/period_builder.ex
Compiled lib/tzdata/far_future_dynamic_periods.ex
Killed

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.