12

How can I use the date command to convert something like "monday week 40" into a ISO date?

I am playing with something like this:

date --date='monday week 40' +'%Y-%m-%d'

And the date I'm searching for would be 2011-10-03.

But my problem is that this date string is not valid, so I need another approach to solve this problem.

/Thanks

Johan
  • 4,583
  • The following link is about what determines on which day of the year a numbered week begins. Week numbering (Wikipedia).. It effectively explains why the 1st of Janunuary of this year is in ISO week 52 .. The %V format sequence used by 'user unknown' reports the ISO week number. – Peter.O Sep 01 '11 at 16:16

3 Answers3

5

An alternative approach:

date --date "+$((40-$(date +%V)))weeks last monday"  +"%F"
  • 40 is the week you search for
  • date +%V returns the current week (35)
  • 40-35 = 5, which is the number of weeks to add
  • from there, seek the last monday
Johan
  • 4,583
user unknown
  • 10,482
  • good one, and it works with my custom date setting. – Peter.O Sep 01 '11 at 14:31
  • This is a clever idea, but it doesn't work. For example, if today is Monday in week 41 (i.e. date +%V returns 41), then the --date parameter value will be +-1weeks last monday, which is actually a fortnight ago, not 7 days ago. – Adam Spiers Sep 02 '13 at 11:09
  • I'm not sure whether I understand your critique. It's 2013 this year, so the example from the question doesn't fit. What should be the absolute date for the question, and what does my approach return instead (maybe: why)? – user unknown Sep 02 '13 at 22:32
  • @AdamSpiers: My calendar displays as Monday, week 40 the 30th of Sep. which is what my algo yields (today). – user unknown Sep 02 '13 at 22:38
  • @userunknown That's because you are testing your code today, which is a Tuesday, which comes after Monday. If you had tested your code yesterday, it would have broke. To make it more obvious, try running date -d 'last monday'. It will return yesterday. What do you think it would have said if you had run it yesterday? – Adam Spiers Sep 03 '13 at 13:38
  • Well, at least if I ask for last tuesday today, date -d 'last tuesday' I get Di 27. Aug 00:00:00 CEST 2013 (which is last tuesday in German locale). – user unknown Sep 03 '13 at 21:22
4

Really ugly and probably works only with GNU date:

date -d "$( date -d "$( date +'%Y-01-01' ) +40 weeks") -$( date -d "$( date +'%Y-01-01' ) +40 weeks" +'%w' ) days+1 day" +'%Y-%m-%d'

Tested only for your 3 October example, may fail for some other cases.


Update: If you have a non eng locale you need to specify the output from the inner date to get to to work. (And %F just is YYYY-MM-DD).

date -d "$(date -d "$(date +'%Y-01-01') +40 weeks" +"%F") -$(date -d "$(date +'%Y-01-01') +40 weeks" +%w) days +1 day" +"%F"
Johan
  • 4,583
manatwork
  • 31,277
  • 1
    You missed to format the output from the inner date so the outer could use it correctly. – Johan Sep 01 '11 at 11:19
  • @Johan, I had no problem with using the default format. Maybe it is locale specific? I use en_US. Good point anyway. – manatwork Sep 01 '11 at 11:34
  • For the date I use the Swedish locale, so there is the difference. – Johan Sep 01 '11 at 13:09
  • Thanks for the locale adjustment. I have a custom date format and had the same problem.. I had almost sorted it out, but now you've posted it I'll use your tweak; it's better. – Peter.O Sep 01 '11 at 14:32
  • There was no requirement for this to be a one-liner. It would be better to split this into multiple lines, using temporary variables with descriptive names to make it clear how it works. It also assumes that Jan 1st is in the same week number each year, which is not the case as already noted by @Peter.O. – Adam Spiers Sep 02 '13 at 11:16
1

OK, here's my attempt. It steals ideas from the other answers, and attempts to make the logic easier to follow. This is based on the ISO 8601 system, so it won't be correct if you live in countries such as USA or Canada, but should be easily adjustable for those countries.

# sets $week_start to a representation of Monday of the given week
# number formatted via the given format, and similarly sets
# $week_end to Friday of the same week.
get_week_range () {
    week_num="$1" date_format="$2"

    # Most of the world adhere to ISO 8601 which states that weeks begin on Monday
    # and Jan 4th is always in week #1:
    #
    #   http://en.wikipedia.org/wiki/ISO_week_date
    #
    # For other week numbering systems (e.g. USA, Canada), see:
    #
    #   http://en.wikipedia.org/wiki/Seven-day_week#Week_numbering
    day_in_week_1=$( date +'%Y-01-04' )
    day_num_in_week_1=$( date -d $day_in_week_1 +%u ) # 1 is Monday
    days_from_week_1_start=$(( $day_num_in_week_1 - 1 ))
    # This is a Monday:
    start_of_week_1=$( date -d "$day_in_week_1 - $days_from_week_1_start days" +%F )

    week_delta="$(( $week_num - 1 ))"
    # Monday:
    week_start=$( date -d "$start_of_week_1 + $week_delta weeks"          +"$date_format" )
    # Friday:
    week_end=$(   date -d "$start_of_week_1 + $week_delta weeks + 4 days" +"$date_format" )
}