Giter VIP home page Giter VIP logo

calendrical's Introduction

Calendrical

Calendrical provides calendar-related functions that build upon the conversion capabilities of Calendar available in Elixir from verison 1.5.0.

Calendrical implements:

  • K-Day calculations in Calendrical.Kday

Example Usage

Date.new/4 is used to create a calendar with the default calendar being Calendar.ISO. To create a date using one of the Calendrical calendars simply:

iex> Date.new(2017,1,1,Calendrical.Calendar.Gregorian)
{:ok,
 %Date{calendar: Calendrical.Calendar.Gregorian, day: 1, month: 1, year: 2017}}

iex> Date.new(2017,1,1,Calendrical.Calendar.Egyptian)
{:ok,
 %Date{calendar: Calendrical.Calendar.Egyptian, day: 1, month: 1, year: 2017}}

To convert a date from one calendar to another use the Date.convert/2 or Date.convert!/2 functions. For example:

iex> Date.convert! ~D[2016-07-01], Calendrical.Calendar.Julian
%Date{calendar: Calendrical.Calendar.Julian, day: 18, month: 6, year: 2016}

Note that dates can only be converted if the calendars both have the same definition of the start of day. Some calendars define the start of day various as sunrise, sunset, noon and midnight. To convert calendars with different notions of when the day starts the time of day will need to be specified hence DateTime.convert/2 is required.

iex> dt1 = %DateTime{calendar: Calendar.ISO, day: 29, hour: 23, microsecond: {0, 0},
 minute: 0, month: 2, second: 7, std_offset: 0, time_zone: "America/Manaus",
 utc_offset: -14400, year: 2000, zone_abbr: "AMT"}

iex> DateTime.convert(dt1, Calendrical.Calendar.Julian)
{:ok,
 %DateTime{calendar: Calendrical.Calendar.Julian, day: 16, hour: 23, microsecond: {0, 6},
  minute: 0, month: 2, second: 7, std_offset: 0, time_zone: "America/Manaus",
  utc_offset: -14400, year: 2000, zone_abbr: "AMT"}}

Roadmap

  • Date and time formatting which will be done in a locale sensitive way through the ex_cldr package after it is updated to provide that support. Expected in July 2017.

  • Hebrew and Islamic calendars (the arithmetic versions) are expected to land in July 2017

  • Astronomical calendar types will be implemented but only after the required astronomy library is built (ie not expected before year end 2017)

Elixir Version Support

Calendrical requires Elixir 1.5 or later. It is tested on Elixir 1.5.0-rc.0

Installation

  1. Add calendrical to your list of dependencies in mix.exs:
    def deps do
      [{:calendrical, "~> 0.1.2"}]
    end
  1. Ensure calendrical is started before your application:
    def application do
      [applications: [:calendrical]]
    end

The docs can be found at https://hexdocs.pm/calendrical

calendrical's People

Contributors

kipcole9 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

tmbb

calendrical's Issues

Wrong codepoints for superscripts

Module Calendrical.Math.Fraction in file math.ex.
From the @doc of function to_string:

  ## Example
      iex> Calendrical.Math.Fraction.to_string {2, {16, 25}}
      "2ⁱ⁶⁄₂₅"

The numerator contains the character "i" instead of "1".
The codepoint for digit "3" is missing.
These changes of function superscript help:

@spec superscript(integer) :: String.t
- def superscript(digit) when digit in [0,1,4,5,6,7,8,9] do   # always catches digit '1'
+ def superscript(digit) when digit in [0,4,5,6,7,8,9] do     # `1` deleted
    <<226, 129, 176 + digit>>
  end
- def superscript(1), do: "\u2071"    # this produces character "ⁱ" instead of digit "¹"
+ def superscript(1), do: "\u00b9"    # correct codepoint
  def superscript(2), do: "\u00b2"
+ def superscript(3), do: "\u00b3"    # additional codepoint

Alternate calculation of Julian leap year

May I suggest to replace the functions

  def leap_year?(year) when year > 0 do
    Math.mod(year, 4) == 0
  end

  def leap_year?(year) do
    Math.mod(year, 4) == 3
  end

in module Calendrical.Calendar.Julian by an alternative that doesn't use the Math helper module and uses only one function:

def leap_year_alt?(year) do
    (year > 0) && (rem(year, 4) == 0) || (rem(year, 4) == -1)
  end

Afterall we know that year is an integer. The term (rem(year, 4) == -1) takes into account that Erlang produces a negative modulo for negative numbers. In other languages (i.e. Python) this would have been (year % 4) == 3 for negative years.

I tested the new function against the old one using:

  test "Julian.leap_year?(year)" do
    for year <- -4717..2020 do
      assert Julian.leap_year_alt?(year) === Julian.leap_year?(year)
    end
  end

All tests produced the same results and passed.
Of course, if accepted, leap_year_alt?, should be renamed leap_year?, so that no outer depencies will be broken.

Compilation error in latest calendrical version

I downloaded and unzipped 'calendrical' into a new directory. Then I did a 'mix deps.get' which was OK. But when I did a 'mix do clean, compile' I got a compilation error:

`D:\Projekte\Chronos\calendrical>mix do clean, compile
Compiling 12 files (.ex)
warning: function naive_datetime_from_iso_days/1 required by behaviour Calendar is not implemented (in module Calendrical.Calendar.Armenian)
  lib/calendrical/calendar/armenian.ex:1


== Compilation error in file lib/calendrical/calendar/julian.ex ==
** (UndefinedFunctionError) function Calendar.ISO.naive_datetime_to_rata_die/7 is undefined or private. Did you mean one of:

      * naive_datetime_from_iso_days/1
      * naive_datetime_to_iso8601/7
      * naive_datetime_to_iso8601/8
      * naive_datetime_to_iso_days/7
      * naive_datetime_to_string/7

    (elixir) Calendar.ISO.naive_datetime_to_rata_die(0, 12, 30, 0, 0, 0, {0, 6})
    lib/calendrical/calendar/julian.ex:6: (module)
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6`


Some general feedback

Here are some notes, after having glanced over the library during breakfast.

  • Calendrical:

    • The naming of days/1 for a function that returns the number of what day 'monday' is feels counter-intuitive to me. Maybe weekday_number/1 or something similar is better. Besides, the names of the weekdays (and even if there are seven days inside) depend on the actual calendar and language used, so maybe this should better be moved to another module (Such as Kday).
    • Probably, the datetime-geared functions should be removed. %DateTime{} stores the timezone offset on top of what NaiveDateTime does. At least Elixir's standard library takes the approach of having developers explicitly think about this timezone management (and thus always having the explicit NaiveDateTime -> DateTime conversion step).
      • For this library it is unfortunate that some of the RataDie-calculations inside Elixir's standard library are managed in private functions. Maybe an alternate idea would be to create a %RataDie{} calendar implementation (with trivial naive_datetime_to_rata_die and naive_datetime_from_rata_die-implementations).
  • Calendrical.Math:

    • At least the angles_to_radians functionality is not required by any calendars, as far as I know (or is it? 😁 )
    • It is worth noting that Integer (courtesy of the Calendar additions with the Rata Die day fraction calculations) now contains a gcd/2.
  • Calendrical.JulianDay:

    • line 58 contains a magic number. Probably better to create a constant for the middle of the day.
    • I don't actually think there is a reason to work with microsecond-precision day fractions here. You could just use the lowest fraction that allows you to express something. For noon, this would be {1, 2}.
    • Line 84 might convert the result to a float, which is probably not what you want.
    • Why is Calendrical.JulianDay not a Calendar behaviour implementation?
  • Calendrical.Kday:

    • Seems fine, although it is been a while since I read the K-day part of the Calendrical Calculations paper. 😅

Thank you for writing this! ❤️

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.