Closed dbernheisel closed 4 years ago
@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: :-)
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.
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
iex> Cldr.Calendar.Interval.week ~D[2020-04-05 MyApp.Calendar.US]
iex> Cldr.Calendar.day_of_week ~D[2020-04-05 MyApp.Calendar.US]
7
3. If you're doing calendar formatting then you might get some ideas from [ex_cldr_calendars_format](https://github.com/elixir-cldr/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
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.
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 :-)
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.
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!
I have opened an issue on ex_cldr_calendars_format
to continue the discussion.
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.
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
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.
I see that this is straight from the Cldr data; so the missing link (I'm assuming) is the supplemental data.