Modify

Opened 13 years ago

Closed 11 years ago

#8175 closed enhancement (fixed)

Add week numbers to calendar

Reported by: anonymous Owned by: Steffen Hoffmann
Priority: normal Component: WikiCalendarMacro
Severity: normal Keywords: week number calendar
Cc: Ryan J Ollos, Jun Omae Trac Release: 0.11

Description

Great macro :-)

It would be even grater if one could display week numbers in the calendar.

Attachments (3)

20130406_wrong-weeknum_by_Babel_format_date.png (7.5 KB) - added by Steffen Hoffmann 11 years ago.
wrong week numbers because of two week numbers for 1 week
test-weeknum.py (1.1 KB) - added by Jun Omae 11 years ago.
default-accept-language-from-mozilla-org-l10n-central.txt (3.2 KB) - added by Jun Omae 11 years ago.

Download all attachments as: .zip

Change History (19)

comment:1 Changed 13 years ago by Steffen Hoffmann

Replying to anonymous:

Great macro :-)

Thank you.

It would be even grater if one could display week numbers in the calendar.

Uh, well. Certainly I'd have used this too, but hesitated to add such a feature after digging into the issue a bit, as there is no easy way, because there is NO universal definition worldwide. [1][2]

I'll leave this as a hint for further development, but without a patch to start on you'll most probably not see this happening soon, at least not this year, sorry.

[1] http://en.wikipedia.org/wiki/Week_number#Week_numbering
[2] http://www.pjh2.de/datetime/weeknumber/wnd.php?l=en

comment:2 in reply to:  1 Changed 11 years ago by Steffen Hoffmann

Component: WikiTicketCalendarMacroWikiCalendarMacro

Replying to hasienda:

... hesitated to add such a feature after digging into the issue a bit, as there is no easy way, because there is NO universal definition worldwide.

Sure, but we could still attempt it at least and stick to an ISO standard as done for first-day-of week (#7639). And let's make this feature available to both wiki macros in the united code base too.

comment:3 Changed 11 years ago by Steffen Hoffmann

Cc: Ryan J Ollos Jun Omae added; anonymous removed

My initial implementation was:

def _get_weeknumber(dt, week_start, locale=None):
    if has_babel:
        from babel.dates import format_date
        return int(format_date(dt, 'w', locale=locale))
    else:
        if week_start == 6:
            return int(dt.strftime('%U'))
        return int(dt.strftime('%W'))

It took me about two working days to figure out, that neither Python core modules nor Babel do handle week numbering according to established common standards.

In fact, in weeks bridging years I see different week numbers assigned to days of the old year vs. days of the new year, effectively increasing the number of weeks to 53/54 instead of expected 52/53! Even in Babel calculation seems to unconditionally count from week with 1st of Jan as week 1 (the US definition) for any locale I tried.

So I've researched more and done an own calculation. I never dreamed, it could become that complicated again, after significant simplifications for the whole calendar build algorithm by introducing Babel lately (#10992).

I'll implement automatic switching between ISO (default) and US rule (if detecting first weekday at == Sunday), and allow for pinning individual calendar instances to on of three different numbering schemes, selected by an half-intuitive number:

1
week 1 is the week with Jan 01. (US)
4
week 1 is the week with Jan 04. (ISO)
7
week 1 is the week with Jan 07. Pakistan, maybe others

Reference: http://www.pjh2.de/datetime/weeknumber/wnd.php?l=en

comment:4 in reply to:  3 ; Changed 11 years ago by Jun Omae

Even in Babel calculation seems to unconditionally count from week with 1st of Jan as week 1 (the US definition) for any locale I tried.

In Babel, the week of year depends on locale with territory.

>>> from babel.dates import format_date
>>> from datetime import date
>>> format_date(date(2006, 1, 1), format='w', locale='en_US')
u'1'
>>> format_date(date(2006, 1, 1), format='w', locale='de')
u'1'
>>> format_date(date(2006, 1, 1), format='w', locale='de_DE')
u'52'

But, in Trac, the locales except some locales have no territory attribute. In the case, it can use babel.core.LOCALE_ALIASES to map lang to lang-territory (e.g. de to de_DE).

See also:

comment:5 in reply to:  4 ; Changed 11 years ago by Steffen Hoffmann

Replying to jun66j5:

Even in Babel calculation seems to unconditionally count from week with 1st of Jan as week 1 (the US definition) for any locale I tried.

In Babel, the week of year depends on locale with territory.

Oh, I clearly missed that yet.

But, in Trac, the locales except some locales have no territory attribute. In the case, it can use babel.core.LOCALE_ALIASES to map lang to lang-territory (e.g. de to de_DE).

Now I've seen the work you've already done last year on the issue for Trac core. Nice, and thanks for the pointers.

What I still do not understand: Wouldn't it be sensible to at least try to rather take the territory from the complete req.language listing than let Babel guess it from possibly truncated language setting in Trac right-away?

comment:6 Changed 11 years ago by Steffen Hoffmann

But go only one or two years further on to see, that calculation is wrong even with locale including territory information:

>>> date(2008, 12, 31).weekday()
2
>>> date(2009, 1, 1).weekday()
3
>>> format_date(date(2008, 12, 31), format='w', locale='de_DE')
u'53'
>>> format_date(date(2009, 1, 1), format='w', locale='de_DE')
u'1'

The week number changes between Tuesday and Wednesday. It shouldn't, right? As long as you look on the first day of the week and display that week number, you won't see the difference. But it is obviously there.

comment:7 Changed 11 years ago by Steffen Hoffmann

Using Babel's format_date:

 Trac[macros] DEBUG: Locale setting for wiki calendar: German (Germany)
 Trac[macros] DEBUG: CALENDAR from 29.12.2008 to 01.02.2009
 Trac[macros] DEBUG: Day 29.12.2008 in week 53
 Trac[macros] DEBUG: Day 30.12.2008 in week 53
 Trac[macros] DEBUG: Day 31.12.2008 in week 53
 Trac[macros] DEBUG: Day 01.01.2009 in week 1
 Trac[macros] DEBUG: Day 02.01.2009 in week 1
 Trac[macros] DEBUG: Day 03.01.2009 in week 1
 Trac[macros] DEBUG: Day 04.01.2009 in week 1
 Trac[macros] DEBUG: Day 05.01.2009 in week 2

and using my standards-conform algo:

 Trac[macros] DEBUG: Locale setting for wiki calendar: German (Germany)
 Trac[macros] DEBUG: CALENDAR from 29.12.2008 to 01.02.2009
 Trac[macros] DEBUG: Day 29.12.2008 in week 1
 Trac[macros] DEBUG: Day 30.12.2008 in week 1
 Trac[macros] DEBUG: Day 31.12.2008 in week 1
 Trac[macros] DEBUG: Day 01.01.2009 in week 1
 Trac[macros] DEBUG: Day 02.01.2009 in week 1
 Trac[macros] DEBUG: Day 03.01.2009 in week 1
 Trac[macros] DEBUG: Day 04.01.2009 in week 1
 Trac[macros] DEBUG: Day 05.01.2009 in week 2

comment:8 in reply to:  5 Changed 11 years ago by Steffen Hoffmann

Replying to hasienda:

Replying to jun66j5:

But, in Trac, the locales except some locales have no territory attribute. In the case, it can use babel.core.LOCALE_ALIASES to map lang to lang-territory (e.g. de to de_DE).

Now I've seen the work you've already done last year on the issue for Trac core. Nice, and thanks for the pointers.

What I still do not understand: Wouldn't it be sensible to at least try to rather take the territory from the complete req.language listing than let Babel guess it from possibly truncated language setting in Trac right-away?

This one from inside expand_macro is not fully tested yet, especially not with Trac down to 0.11, but as you'll see, I did already care for things like non-existent attributes (if someone uses Babel + Trac-0.11 combined).

        # Respect user's locale, if available.
        try:
            loc_req = str(formatter.req.locale)
        except AttributeError:
            # Available since Trac 0.12.
            loc_req = None
        loc = None
        if has_babel:
            if loc_req:
                try:
                    loc = Locale.parse(loc_req)
                except UnknownLocaleError:
                    pass
                if loc and not loc.territory:
                    try:
                        for loc_req in formatter.req.languages:
                            loc = Locale.parse(loc_req.replace('-', '_'))
                            break # first one rules
                    except (AttributeError, UnknownLocaleError):
                        pass
            if not loc:
                # Try system default.
                loc = Locale.default('LC_TIME')
            if loc and not loc.territory and loc.language in LOCALE_ALIASES:
                loc = Locale.parse(LOCALE_ALIASES[loc.language])
            if not loc:
                # Default fallback.
                loc = Locale('en', 'US')
            env.log.debug('Locale setting for wiki calendar: %s'
                          % loc.get_display_name('en'))

I try to get the missing territory info from the first of browser's preferred languages, and only after that fails I do resort to guessing it with Babel as suggested.

Changed 11 years ago by Steffen Hoffmann

wrong week numbers because of two week numbers for 1 week

comment:9 in reply to:  6 ; Changed 11 years ago by Steffen Hoffmann

Replying to hasienda:

The week number changes between Tuesday and Wednesday. It shouldn't, right? As long as you look on the first day of the week and display that week number, you won't see the difference.

Not true, you see it, because the next week after the 'mixed' on is (correctly) week 2:

wrong week numbers because of two week numbers for 1 week

Ultimately, 29-Dec-2009 needs to get week number 1 assigned for German locale settings.

Changed 11 years ago by Jun Omae

Attachment: test-weeknum.py added

comment:10 in reply to:  9 Changed 11 years ago by Jun Omae

Ultimately, 29-Dec-2009 needs to get week number 1 assigned for German locale settings.

Hmmm, it seems that Babel has the issues about week number....

And so, I found the workaround. Retrieving week number, use last day in the week instead of first day. See test-weeknum.py.

>>> from babel.dates import format_date
>>> from datetime import date
>>> format_date(date(2008, 12, 29), format="yyyy-MM-dd YYYY'W'ww", locale='de_DE')
u'2008-12-29 2008W53'
>>> format_date(date(2009, 1, 4), format="yyyy-MM-dd YYYY'W'ww", locale='de_DE')
u'2009-01-04 2009W01'
$ python2.4 ./test-weeknum.py 2006 2009 de_DE
        | Mo. Di. Mi. Do. Fr. Sa. So.
2006W52 | 25  26  27  28  29  30  31
2007W01 |  1   2   3   4   5   6   7

        | Mo. Di. Mi. Do. Fr. Sa. So.
2008W01 | 31   1   2   3   4   5   6
2008W02 |  7   8   9  10  11  12  13

        | Mo. Di. Mi. Do. Fr. Sa. So.
2009W01 | 29  30  31   1   2   3   4
2009W02 |  5   6   7   8   9  10  11

        | Mo. Di. Mi. Do. Fr. Sa. So.
2009W53 | 28  29  30  31   1   2   3
2010W01 |  4   5   6   7   8   9  10

comment:11 in reply to:  5 ; Changed 11 years ago by Jun Omae

What I still do not understand: Wouldn't it be sensible to at least try to rather take the territory from the complete req.language listing than let Babel guess it from possibly truncated language setting in Trac right-away?

Oh, that makes sense. However, AFAIK, most browsers send Accept-Language header without country code if not English (e.g. en-US, en-GB) nor Chinese (e.g. zh-CN, zh-TW).

Example in Chrome with Japanese settings:

Accept-Language:ja,en-US;q=0.8,en;q=0.6

comment:12 in reply to:  11 ; Changed 11 years ago by Steffen Hoffmann

Replying to jun66j5:

What I still do not understand: Wouldn't it be sensible to at least try to rather take the territory from the complete req.language listing than let Babel guess it from possibly truncated language setting in Trac right-away?

Oh, that makes sense. However, AFAIK, most browsers send Accept-Language header without country code if not English (e.g. en-US, en-GB) nor Chinese (e.g. zh-CN, zh-TW).

Hm, it may depend on browser brand and more. I'm testing with FF3@Debian with 6 or more languages in settings, and they all make it through to req.languages (de-de followed by de, en-us, us, ru, ja), so my proposed logic works great. While we're discussing, maybe I should propose it for inclusion in Trac core too? And file a ticket against Babel? I'll do this at least after resolving my issue with this plugin.

Btw, great to have the discussion here. I see, how developers in very different locations and with different view points get further than same number would do in one place. Thank you.

comment:13 in reply to:  12 ; Changed 11 years ago by Jun Omae

While we're discussing, maybe I should propose it for inclusion in Trac core too? And file a ticket against Babel? I'll do this at least after resolving my issue with this plugin.

Sure. After trac:r11776, Trac now searches in req.languages for "first week day" if the locale has no territory. Thanks again, Steffen!

comment:14 Changed 11 years ago by Steffen Hoffmann

(In [12989]) WikiCalendarMacro: Add optional week numbers, refs #1145, #7639 and #8175.

Rationale and constraints of current implementation:

  • support any calendar per instance (use 'w' key-word) - no dependencies
  • use basic start-of-week negotiation, if Babel is not installed
  • use auto-negotiation for locale-aware Trac versions (since Trac 0.12)
  • use advanced locale detection (similar to Trac 1.0.2)

Because I've found an issue with week number calculation in Babel, this plugin does it on its own for now.

comment:15 in reply to:  13 Changed 11 years ago by Steffen Hoffmann

Replying to jun66j5:

While we're discussing, maybe I should propose it for inclusion in Trac core too? ...

Sure. After trac:r11776, Trac now searches in req.languages for "first week day" if the locale has no territory. Thanks again, Steffen!

I've been lucky to re-use some of your code improvements in turn as well. Thank you too.

comment:16 Changed 11 years ago by Steffen Hoffmann

Resolution: fixed
Status: newclosed

(In [12991]) WikiCalendarMacro: Releasing current, tested macro package as final product, closes #7639, #8175, #9718, #10991, #10992 and #10993.

Special thanks to Jun Omae for pushing development by testing and providing valuable hints in our discussion about utilizing Babel for better localization and for making macro execution thread-safe as well.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Steffen Hoffmann.
The resolution will be deleted. Next status will be 'reopened'.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.