1

I can only find algorithm for getting ISO 8601 week (week starts on a Monday).

However, the iCal spec says

A week is defined as a seven day period, starting on the day of the week defined to be the week start (see WKST). Week number one of the calendar year is the first week that contains at least four (4) days in that calendar year.

Therefore, it is more complex than ISO 8601 since the start of week can be any day of the week.

Is there an algorithm to determine what is the week number of a date, with a custom start day of week?

or... is there a function in iCal4j that does this? Determine a weekno from a date?

Thanks!

p.s. Limitation: I'm using a JVM language that cannot extend a Java class, but I can invoke Java methods or instantiate Java classes.

Community
  • 1
  • 1
Henry
  • 32,689
  • 19
  • 120
  • 221
  • And I presume jodatime is not an option any more than abusing yourself with java.util.Calendar is? – Tetsujin no Oni Jan 25 '12 at 20:43
  • The iCal week number is defined the same way as the ISO8601 week number according to that link. Looks like the question you're driving at is dealt with here: http://stackoverflow.com/q/1801907/93922 – Tetsujin no Oni Jan 25 '12 at 22:09
  • @TetsujinoOni not really. iCal makes use of a WKST variable that defines which day is the start of a week. Although it is Monday by default, like ISO8601, but it can be any day of the week. – Henry Jan 25 '12 at 23:11
  • Looking at JodaTime in a little more detail I think a custom chronology set up to rebase using your WKST, combined with weekyear() and weekOfWeekyear() will get you where you're going. – Tetsujin no Oni Jan 25 '12 at 23:50
  • @TetsujinnoOni I looked at `org.joda.time.chrono.ISOChronology`, but I can't easily 'rebase' it. I guess I still need to write a new object that extends `org.joda.time.chrono.BaseChronology`, but I cannot write a new object 'cause I'm using a JVM language that does not let me write a new class. – Henry Jan 26 '12 at 00:08
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/7059/discussion-between-tetsujin-no-oni-and-henry) – Tetsujin no Oni Jan 26 '12 at 00:09
  • found this: http://www.cflib.org/udf/customWeekNumber might work, but haven't tested. – Henry Jan 26 '12 at 00:39

2 Answers2

4
if (input_date < firstDateOfTheYear(WKST, year))
{
    return ((isLeapYear(year-1))?53:52);
}
else
{
    return ((dayOfYear(input_date) - firstDateOfTheYear(WKST, year).day)/7 + 1);
}

firstDateOfTheYear returns the first calendar date given a start of week(WKST) and the year, e.g. if WKST = Thursday, year = 2012, then it returns Jan 5th.

dayOfYear returns sequencial numerical day of the year, e.g. Feb 1st = 32

Example #1: Jan 18th, 2012, start of week is Monday

  • dayOfYear(Jan 18th, 2012) = 18
  • firstDateOfTheYear(Monday, 2012) = Jan 2nd, 2012

(18 - 2)/7 + 1 = 3 Answer Week no. 3

Example #2: Jan 18th, 2012, start of week is Thursday

  • dayOfYear(Jan 18th, 2012) = 18
  • firstDateOfTheYear(Thursday, 2012) = Jan 5th, 2012

(18 - 5)/7 + 1 = 2 Answer Week no. 2

Example #3: Jan 1st, 2012, start of week is Monday

  • firstDateOfTheYear(Monday, 2012) = Jan 2nd, 2012
  • IsLeapYear(2012-1) = false

Jan 1st, 2012 < Jan 2nd, 2012 Answer Week no. 52

vkoo
  • 41
  • 2
  • Jan 1, 2009, with WKST = Monday. First Monday of 2009 is the 5th, but Jan 1, 2009 is on week 1, not last week of the previous year. This algorithm is broken. See http://www.personal.ecu.edu/mccartyr/isowdcal.html – Henry Jan 26 '12 at 08:04
  • Good point! This is because my first condition: 'if(input_date < firstDateOfTheYear(WKST, year))' is too naive. It didn't take into account your requirement "4 days or above = a week". You likely need to put another condition like if firstDateOfTheYear.GetDay() > 4, then all the dates before that day has to be week 1 and subsequent weeks have to be + 1. I'm sure you can figure out how to refine the pseudo code to fit that logic in ;) – vkoo Jan 26 '12 at 19:16
  • This also makes Example #2 invalid. Answer should be week no.3 because there are 4 days before Jan 5th, 2012 that should be considered as week no.1. – vkoo Jan 26 '12 at 19:22
2
  1. Let daysInFirstWeek be the number of days on the first week of the year that are in January. Week starts on a WKST day. (e.g. if Jan 1st is a WKST day, return 7)

  2. Set dayOfYear to the n-th days of the input date's year (e.g. Feb 1st = 32)

  3. If dayOfYear is less than or equal to daysInFirstWeek

    3.1. if daysInFirstWeek is greater than or equal to 4, weekNo is 1, skip to step 5.

    3.2. Let daysInFirstWeekOfLastYear be the number of days on the first week of the previous year that are in January. Week starts on a WKST day.

    3.3. if daysInFirstWeekOfLastYear is 4 or last year is Leap year and daysInFirstWeekOfLastYear is 5, weekNo is 53, otherwise weekNo is 52, skip to step 5.

  4. Set weekNo to ceiling((dayOfYear - daysInFirstWeek) / 7)

    4.1. if daysInFirstWeek greater than or equal to 4, increment weekNo by 1

    4.2. if daysInFirstWeek equal 53 and count of days on the first week (starting from WKST) of January in the year of inputDate's year + 1 is greater than or equal to 4, set weekNo to 1

  5. return weekNo

Henry
  • 32,689
  • 19
  • 120
  • 221
  • I suppose that 4.2 should be: 4.2. if weekNo equal 53 and count of days on the first week (starting from WKST) of January in the year of inputDate's year + 1 is greater than or equal to 4, set weekNo to 1 – BladeWise Nov 13 '13 at 11:10