Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Calendar with Sunday as first day of week #4

Closed
dbernheisel opened this issue Apr 4, 2020 · 7 comments
Closed

[Question] Calendar with Sunday as first day of week #4

dbernheisel opened this issue Apr 4, 2020 · 7 comments

Comments

@dbernheisel
Copy link

This may be more of a "how to use" question than an issue.

In the US, the default calendar starts with the first day of the week as Sunday. How do I use ex_cldr and ex_cldr_calendars to localize the calendar for US users to have the day of the week reflected with Sunday = 1?

The supplemental CLDR data for the territory US has a preference for this, but I'm not sure that's being used or parsed. Since it's territory-specific, I'm not sure if this belongs here or in ex_cldr_territories

https://unicode.org/cldr/charts/latest/supplemental/territory_information.html#US
http://demo.icu-project.org/icu-bin/locexp?d_=en&_=en_US

image

Ultimately, I'd like to be able to put a locale in as "en-Latn-US", and have the preferred calendar become something like Cldr.Calendar.EnLatnUS, or a way to provide a mapping of locales to pre-defined calenadrs (defined either by Cldr or by the application).

The closest I can get so far is ordering Sunday first in the list, but the day_of_week still reflects 7 as Sunday instead of 1.

defmodule MyApp.Calendar.US do
  @moduledoc """
  This is the same as a gregorian Calendar, but with Sunday starting the week.
  """

  use Cldr.Calendar.Base.Month, day_of_week: Cldr.Calendar.sunday(), cldr_backend: MyApp.Cldr
end

# ...

iex(1)> Cldr.Calendar.localize(~D[2020-04-05 MyApp.Calendar.US], :days_of_week)
[
  {7, "Sun"},
  {1, "Mon"},
  {2, "Tue"},
  {3, "Wed"},
  {4, "Thu"},
  {5, "Fri"},
  {6, "Sat"}
]

I see that this is straight from the Cldr data; so the missing link (I'm assuming) is the supplemental data.

@kipcole9
Copy link
Collaborator

kipcole9 commented Apr 5, 2020

@dbernheisel thanks for the issue. I need to think on this a little but I can clarify one thing: day_of_week is always 1..7 where 1 is Monday. Its an internal representation of the calendar day of week (ie not localised).

There's one bug I will fix, one question I have and one suggestion: :-)

  1. Cldr.Calendar.new/3 currently takes a :locale option and is intended to return a calendar configured for that locale. It is not honouring the first_day_in_week preference. Thats a bug and I'll fix it. This will at least give you the right calendar with minimal effort.

  2. The second part depends on your use case I think. Can you describe more what you are trying to do that isn't working as expected? Using the ordinal number of the day of the week isn't that common since its an internal representation. You may find Cldr.Calendar.Interval.week/{1, 2} to be of some help since it returns a date range of days for a week. For example:

# With year and week
iex> Cldr.Calendar.Interval.week 2020, 1, MyApp.Calendar.US                                       
#DateRange<~D[2020-01-05 MyApp.Calendar.US], ~D[2020-01-11 MyApp.Calendar.US]>
iex> Cldr.Calendar.day_of_week ~D[2020-01-05 MyApp.Calendar.US]
7

# With a date
iex> Cldr.Calendar.Interval.week ~D[2020-04-05 MyApp.Calendar.US]
#DateRange<~D[2020-04-05 MyApp.Calendar.US], ~D[2020-04-11 MyApp.Calendar.US]>
iex> Cldr.Calendar.day_of_week ~D[2020-04-05 MyApp.Calendar.US]  
7
  1. If you're doing calendar formatting then you might get some ideas from ex_cldr_calendars_format which does formatting in a calendar-specific way including putting the right first day of week in the right place. I just pushed a small update to fix a bug, but also added a test with your calendar to illustrate.

An example of output for April 2020 with your calendar:

April 2020

Sun Mon Tue Wed Thu Fri Sat
29 30 31 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 1 2
3 4 5 6 7 8 9

@dbernheisel
Copy link
Author

dbernheisel commented Apr 5, 2020

Ah perfect that's what I was essentially looking for, but building my own HTML formatter without ex_cldr_calendars_format.

Here's what I have right now:

# ./config/config.exs
config :ex_cldr,
  default_backend: MyAppWeb.Cldr,
  default_locale: "en",
  json_library: Jason

# ./lib/my_app_web/cldr.ex
defmodule MyAppWeb.Cldr do
  use Cldr,
    otp_app: :my_app,
    gettext: MyAppWeb.Gettext,
    providers: [Cldr.Calendar, Cldr.DateTime, Cldr.Number, Cldr.Unit, Cldr.List, Cldr.Territory]
end

# ./lib/my_app_web/cldr_calendars.ex
defmodule MyAppWeb.Calendar.US do
  @moduledoc """
  This is the same as a regular Calendar, but with Sunday starting the week.
  """

  use Cldr.Calendar.Base.Month,
    month_of_year: 1,
    min_days_in_first_week: 1,
    day_of_week: Cldr.Calendar.sunday(),
    cldr_backend: MyAppWeb.Cldr

end


# Usage in iex to test
iex> date = ~D[2020-04-05 MyAppWeb.Calendar.US]
~D[2020-04-05 MyAppWeb.Calendar.US]

iex> Cldr.Calendar.localize(date, :days_of_week)
[
  {7, "Sun"},
  {1, "Mon"},
  {2, "Tue"},
  {3, "Wed"},
  {4, "Thu"},
  {5, "Fri"},
  {6, "Sat"}
]

iex> Date.day_of_week(date)
7

But I think Date.day_of_week(date) is supposed to be 1 for this US-based calendar. April 5th 2020 is on a Sunday, which is the first day of the week for the US calendar. first_day_of_the_week sounds like the right config to control this behaviour-- is there an option to set this preference?

Looking at Month.day_of_week I see that it ends up calling Elixir.Calendar.ISO.day_of_week where the number is generated. I'm probably misunderstanding something, but would this be where my US-based calendar would need to alter the logic?

I'm essentially trying to build what you have in your example from the ex_cldr_calendars_format above, but I'm currently using Date.day_of_week(date) to determine the position in the calendar rows/columns. I know I could hard-code it, but my hope is to offload this to the Calendar.

But-- now knowing about ex_cldr_calendars_format-- I may just refactor and use your library. Another example of awesome.

@kipcole9
Copy link
Collaborator

kipcole9 commented Apr 5, 2020

I'd be very happy to collaborate on improving ex_cldr_calendars_format - having not looked at the code for a while and revisiting it this morning (my time) I think its pretty solid. You just need to implement a formatter module if you want a formatter different from the ones included (html and markdown.

Date.day_of_week/1 will always return 1..7 where 1 is Monday. Its the day - whereas I think you're referring to the ordinal day of the week which might be a useful function. But really not necessary to generate calendars I think.

Any and all calendars that are based on the Gregorian calendar (which is most but not all of them) delegate to Calendar.ISO where possible. Since all dates have the same meaning in Gregorian calendars (unlike months, weeks and years) we can use Calendar.ISO for individual date functions.

I think its cleaner to use Cldr.Calendar.Interval to generate the week ranges in any case. Thats its job :-)

@kipcole9
Copy link
Collaborator

kipcole9 commented Apr 5, 2020

Let me know too if you are looking to put events on a calendar. I don't have that functionality but I'm definitely interested to implement it. You would pass a map of event => date or date range or list of dates and the formatter would include them appropriately.

@dbernheisel
Copy link
Author

Aha thanks it's my misunderstanding between "ordinal day of week" vs "day of week". Yes I'm developing a mechanism for displaying events on a calendar; I'd love to contribute upstream to ex_cldr_calendar_format after I find some good patterns.

I'll close since you've fully answered the question, and then some!

@kipcole9
Copy link
Collaborator

kipcole9 commented Apr 5, 2020

I have opened an issue on ex_cldr_calendars_format to continue the discussion.

@kipcole9
Copy link
Collaborator

kipcole9 commented Apr 5, 2020

And on a final note ..... as of this commit ex_cldr_calendars now includes Cldr.Calendar.from_locale/2 which will create (or return) a calendar correctly configured for a locale. It's only on GitHub for now - it will be released on hex with a new version of ex_cldr coming with CLDR version 37 later this month.

In addition, the correct defaults for min_days and first_day_of_week are now applied in all cases when creating a calendar.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants