23
$\begingroup$

Consider the following:

AbsoluteTime["17/04/2012",{"Day","/","Month","Year"}];

From my calendar in my office, I know that April 17th is in the 16th week of the year 2012. The Calendar package does not provide a function by which I can determine the week of the year. However, is there a way to determine the week of a year based on AbsoluteTime figures?

$\endgroup$
1
  • 1
    $\begingroup$ If you were interested in the ISO 8601 solution I would suggest to reconsider your accepted answer. Heike's answer gives a wrong 0 for days before week 1. Hans' answer gives the correct week 52 or 53. $\endgroup$
    – stevenvh
    Aug 26, 2012 at 7:25

11 Answers 11

18
$\begingroup$

Since I'm living in Europe I'm sticking to the European definition of week number which is equivalent to the ISO standard. According to this standard, a week starts on Monday and the first week is the week containing 4 January. Taking this into account you could do therefore do something like

weekNumberISO[date_] := Module[{day0, year},
  With[{days = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}},
   year = ToExpression[DateString[date, "Year"]] ; 
   day0 = DatePlus[{year, 1, 4}, 
      {1 - Position[days, DateString[{year, 1, 4}, "DayNameShort"]][[1, 1]], "Day"}];
   1 + Floor[DateDifference[day0, date, "Week"][[1]]]]]

For the North-American definition of week number, i.e. week 1 is the week containing 1 January and a week starts on Sunday, you would get something like

weekNumberUS[date_] := Module[{day0, year},
  With[{days = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}},
   year = ToExpression[DateString[date, "Year"]] ; 
   day0 = DatePlus[{year, 1, 1}, 
      {1 - Position[days, DateString[{year, 1, 1}, "DayNameShort"]][[1, 1]], "Day"}];
   1 + Floor[DateDifference[day0, date, "Week"][[1]]]]]
$\endgroup$
4
  • $\begingroup$ Wow, this is very nice! +1 $\endgroup$
    – Eli Lansey
    Apr 20, 2012 at 18:02
  • $\begingroup$ ISO8601 all the way for me: I can't understand that you would start a year with a 1 day week :-). But the function doesn't work for the days before week 1; it returns zero for 2012-01-01, which should be week 52 (for some years 53). $\endgroup$
    – stevenvh
    Jul 6, 2012 at 13:24
  • $\begingroup$ @Heike stevenvh is right. Is there a way to avoid these two problems (week 0 and week 53)? $\endgroup$
    – John
    Nov 27, 2012 at 1:12
  • 1
    $\begingroup$ @John - The code in my answer (which you also commented to) gives the correct week numbers. I explained there how you can have a week 53. $\endgroup$
    – stevenvh
    Feb 3, 2013 at 15:11
17
$\begingroup$

You can use DateDifference to find the time between January 1st and April 17th:

DateDifference["Jan. 1", "April 17", "Week"]

(* {15.2857, "Week"} *)

If you want the "week number" as you've put it, you can just do:

Ceiling@First@DateDifference["Jan. 1", "April 17", "Week"]

which gives 16.

Edit based on Szabolcs's comment: To ensure this works for Jan 1., use

1 + Floor@First@DateDifference["Jan. 1", "Jan. 1", "Week"]

which gives 1 rather than 0 from the Ceiling approach.


If you want it to automatically pull the current date, use the DateList function:

DateDifference["Jan. 1", DateList[], "Week"]

(* {15.782, "Week"} *)
$\endgroup$
3
  • 3
    $\begingroup$ The reason I used 1 + Floor[...] instead of Ceiling is to make it work when the difference is zero. (I.e. January 1 is in the first week of the year, not the "zeroth".) +1 for showing that DateDifference can give results in weeks. $\endgroup$
    – Szabolcs
    Apr 20, 2012 at 15:33
  • $\begingroup$ Ah, good call. I missed that. $\endgroup$
    – Eli Lansey
    Apr 20, 2012 at 15:37
  • $\begingroup$ as mmorris said this gives the number of week since Jan 1, not the week number... what if Jan 2 is Monday? $\endgroup$
    – Szabolcs
    Apr 20, 2012 at 16:32
7
$\begingroup$

And finally: this works in Mathematica running on Mac OS X - it's getting the ISO Week number from the Unix shell:

<< "! date -j '+%V'"

16

Although I can't see how to test it without changing the system clock... :)

$\endgroup$
1
  • $\begingroup$ That's perfect (+1). $\endgroup$
    – Jens
    Jul 3, 2012 at 21:57
7
$\begingroup$

Another ISO 8601 week number. Based on the same algorithm as Hans' answer, but much shorter, and verified for years between 1900 and 2099.

weekNrISO[x_] := Module[{date1, 
    weekday = Function[{date}, Flatten[Position[{"Sun", "Mon", "Tue", "Wed", "Thu",
              "Fri", "Sat"}, DateString[date, {"DayNameShort"}], 1]][[1]]]},
    date1 = DateList[{DatePlus[x, Mod[8 - weekday[x], 7] - 3][[1]], 1, 3}];
    Return[IntegerPart[(DateDifference[date1, x] + weekday[date1] + 5)/7]]];

Usage:

weekNrISO[{2012, 8, 28}]  

Demo:

Fri 2010-01-01 -- week 53 (*)
Sat 2010-01-02 -- week 53 (*)
Sun 2010-01-03 -- week 53 (*)
Mon 2010-01-04 -- week 1
Tue 2010-01-05 -- week 1
Wed 2010-01-06 -- week 1
Thu 2010-01-07 -- week 1
Fri 2010-01-08 -- week 1

(*) Heike's code gives here an erroneous week 0.

$\endgroup$
3
  • $\begingroup$ Why would 2010-01-01 return week 53? Doesn't one year only contain 52 weeks? $\endgroup$
    – John
    Nov 27, 2012 at 1:10
  • 1
    $\begingroup$ @John - a year is at least 365 days long, which is 52 weeks + 1 day. If 1 January is week 1 (that's if it's a Monday, Tuesday, Wednesday or Thursday), then that extra day is in the 53th week, provided 1 January of the next year is a Friday, Saturday or Sunday. They're before week 1 because week 1 is the first week with a Thursday in it, so it's not week 1, nor week 52, because week 53 already started. If 1 January is a Friday, Saturday or Sunday then 1 January is the last week of the previous year, and 31 December will be week 52. $\endgroup$
    – stevenvh
    Feb 3, 2013 at 15:31
  • $\begingroup$ @John - Thanks for the upvote (I guess it's yours). Have you considered accepting a different answer, given that Heike's is not correct? (Doesn't have to be mine; mine is derived from Hans' answer.) $\endgroup$
    – stevenvh
    Feb 3, 2013 at 20:11
6
$\begingroup$

According to the Mathematica 10.2 documentation, this is built in since version 6. but I think that this was introduced not too long ago:

In[1]:= d=AbsoluteTime@DateList[{"17/04/2012", {"Day", "/", "Month", "/", "Year"}}]
Out[1]= 3 543 609 600

In[2]:= DateString[d, "Week"]
Out[2]= 16

And we also have

In[3]:= DateString[d, "ISOWeekDate"]
Out[3]= 2012-W16-2
$\endgroup$
6
$\begingroup$

It is apparently not documented, but:

DateValue["ISOWeek"]
(* 11 *)

(Today is 2017-03-15 a.k.a. 2017-W11-3.) The example in the question:

DateValue["17/04/2012", "ISOWeek"]
(* 16 *)

(Note: this doesn't seem to work in DateString.)

$\endgroup$
1
  • $\begingroup$ I used this with DateObject e.g. Select[MyListDateValue, (DateValue[DateObject[#[[1]]], "ISOWeek"] == 8) &] $\endgroup$
    – Rho Phi
    Apr 21, 2021 at 9:02
5
$\begingroup$

Just to add another way. If weeks start on monday and the first week of the year is the one containing the first day of the year.

Needs["Calendar`"];

dl = {Monday -> 1, Tuesday -> 2, Wednesday -> 3, Thursday -> 4, 
   Friday -> 5, Saturday -> 6, Sunday -> 7};

weekNumber[date : {year_, month_, day_}] := 
 Quotient[DaysBetween[{year, 1, 1}, date] + DayOfWeek[date] /. dl, 7]
$\endgroup$
5
$\begingroup$
Needs["JLink`"];
AddToClassPath[ToFileName[{$HomeDirectory,"javafiles","joda-time-2.1"}]];
JavaNew["org.joda.time.DateTime",2012,4,17,0,0]@weekOfWeekyear[]@getAsText[]

You need the Joda Time library for that -- which I highly recommend, because it's magnitudes faster than the M date and time functions, which I know from actual experience doing a lot of benchmarking M functions against Java implementations. Functions like DatePlus and DateDifference used in the accepted answer are implemented in slow top-level symbolic M code, very slow, if I might add. And therefore I have all that already in my init.m, because I launch it by default.

However, I'm a bit confused. The o/p clearly stipulated that the solution had to use AbsoluteTime: "However, is there a way to determine the week of a year based on AbsoluteTime figures?" is the closing sentence, yet the "accepted" solution doesn't use it at all. I remember from MathGroup that a constraint like "... using ..." or otherwise specifying method or algorithm was binding for acceptability. If you think my qualms are pointless, I'd like to emphasize that this oftentimes determines if someone will even bother to reply at all. If the o/p indicates that he/she wants it to be done in a particular way and I have no solution for this, even I may have another solution that works differently, I won't bother and read on. I believe this is how it should be. Please correct me if I'm wrong, I'm a noob here, but anything else just seems self-contradictory -- already from a language viewpoint, has nothing to do with M!

And I wonder why the use of WolframAlpha[...] is acceptable here. It contains bugs, assumptions, splats, and the implementations change, which they fully acknowledge.

$\endgroup$
3
  • $\begingroup$ I use so many Java packages all the time (self-written and others) that I have put Needs["JLink`"] and a ReinstallJava with several memory parameters and half a dozen packages in my init.m. In that case my solution is a mere 76 characters and extremely fast. $\endgroup$ Jul 4, 2012 at 2:39
  • $\begingroup$ I was not aware of using Java within Mathematica. What you wrote sounds interesting. Can you recommend any website or so where I can learn more from implementing java-code into Mathematica and also on available java-scripts? $\endgroup$
    – John
    Nov 27, 2012 at 1:09
  • 1
    $\begingroup$ @John: you may find this interesting: www.jvmtools.net/jcc.html. It's a commercial product that allows you to, among several other things, write and compile and debug Java, Scala, C#, and F# code, directly from your M session. $\endgroup$ Dec 19, 2012 at 17:45
5
$\begingroup$

THis same question was asked a while back on newsgroup

    ISOWeek[x_] := Module[{d2}, 
  d2 = DateList[{ToExpression[ 
      DateString[ 
       DatePlus[ 
        x, {(-(Flatten[ 
               Position[{"Sunday", "Monday", "Tuesday", "Wednesday", 
                 "Thursday", "Friday", "Saturday"}, 
                DateString[DatePlus[x, {-1, "Day"}], {"DayName"}], 
                1]])[[1]] + 4), "Day"}], "Year"]], 1, 3, 0, 0, 0}]; 
  IntegerPart[(DateDifference[d2, x] + 
      Flatten[ 
        Position[{"Sunday", "Monday", "Tuesday", "Wednesday", 
          "Thursday", "Friday", "Saturday"}, 
         DateString[d2, {"DayName"}], 1]][[1]] + 5)/7] 
  ] 

Use as follows

ISOWeek[DateList[{2000, 1, 1, 0, 0, 0}]]
$\endgroup$
2
$\begingroup$

Corrected ...

offset = {"Sun" -> 0, "Mon" -> 86400, "Tue" -> 172800, "Wed" -> 259200,
          "Thu" -> 345600, "Fri" -> 432000, "Sat" -> 518400};

WeekOfYear[date_] := Module[{firstDay},
    firstDay = AbsoluteTime[{ToExpression[DateString[date, "Year"]], 1, 1}];
    Floor[(date - firstDay + DateString[firstDay, "DayNameShort"] /. offset) / 604800] + 1
]

WeekOfYear[AbsoluteTime[{2012, 4, 17}]]

year = 2013
Print["Day                         Week #"];
Scan[ Print[DateString[AbsoluteTime[{year, 1, #}]], " ==> ", 
   WeekOfYear[AbsoluteTime[{year, 1, #}]]] &, Range[8]]

Results:

16
Day                         Week #
Tue 1 Jan 2013 00:00:00 ==> 1
Wed 2 Jan 2013 00:00:00 ==> 1
Thu 3 Jan 2013 00:00:00 ==> 1
Fri 4 Jan 2013 00:00:00 ==> 1
Sat 5 Jan 2013 00:00:00 ==> 1
Sun 6 Jan 2013 00:00:00 ==> 2
Mon 7 Jan 2013 00:00:00 ==> 2
Tue 8 Jan 2013 00:00:00 ==> 2

BZZZZ this does not work it gives the number of 7 day periods from the start of the year. Where is the damn delete button.

Refactored ....

WeekOfYear[date_] :=
     Ceiling[(date - AbsoluteTime[{ToExpression[DateString[date, "Year"]], 1, 1}]) / 604800]

WeekOfYear[AbsoluteTime[{2012, 4, 17}]]

Results: 16


date = AbsoluteTime[{2012, 4, 17}];
Ceiling[(date - AbsoluteTime[{2012, 1, 1}]) / 60 / 60 / 24 / 7]
$\endgroup$
1
$\begingroup$

This seems related and may come handy. Basically same can be achieved by:

WolframAlpha["April 17 2012", {{"TimeInYear", 2}, "ComputableData"}]

"16th week"

But connection to the internet is needed for this.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.