Archive for the ‘Ruby’ tag
Getting the week number of the month
I’m working on a project where I need to get all kinds of information about dates. One of the latest puzzles I ran into was how to determine what week of the month a given date is. I thought of many long ways to do this like iterating through the month and incrementing a counter when I hit Saturday, but that sounded very inefficient and unscalable to me. So I decided to see if I could figure out how to do it mathematically. It was a good puzzle and took me about an hour to figure out (math puzzles aren’t my specialty) but I finally got it. Here is what I came up with:
require 'date' def get_week_of_month(d, iso?=false) dm = Date.new(d.year, d.month, 1)</code> # i is a format string that sets this to use ISO or not i = iso? ? '%u' : '%w' # x is the day of the week of the first day of the month x = dm.strftime(i).to_i + 1 # n is the day number of the month n = d.day # o is an offset used to calculate weeks for months that don't start on # the first day of the month. It essentially makes the month always start # on Sunday (or Monday if ISO). o = (n+(x-1)) # r is the remainder indicator. We have to add 1 if there is a remainder r = (o%7) == 0 ? 0 : 1 return ((o/7) + r).to_i end
The first thing I did was assume that all months start on Sunday which gave me a nice grid to play around with. Then I started playing with the math and realized that if I divide any number by 7 that got me really close. If I dropped the remainder, then add 1 that did it every time. Well, almost. Saturdays were then off by 1 because they evenly divided into 7. That was easy to fix though. I just rounded up the remainder to 1 if it was there and then left it zero if it wasn’t. Hence the “r” variable.
The next problem to tackle was handling the months when the first of the month wasn’t on Sunday. To do this I figured out there would have to be some kind of offset. Simple math showed me the offset was the number of the day of the week of the date I was evaluating plus the day of the week of the first day of the month minus 1. By applying that to the original formula, I essentially reset my calendar to starting on the first Sunday of the month and my original formula began to work again.
The final problem to tackle was supporting the ISO week number standard which has weeks start on Monday instead of Sunday. That was easily solved by just changing the beginning of the month reference point. In ruby, and probably many other languages, that just meant changing the format string from a %w to a %u.
Anyway, this was a really fun puzzle and now I’m glad it’s over so I can move on.
Comprehensive Ruby Date/Datetime Formatting Strings
I’ve searched high and low in the ruby documentation for a comprehensive list of the Date and Datetime formatting strings and haven’t been able to find it. Because I use this so often, I decided to post it on my blog for my own reference. I hope any other readers will find it helpful as well.
%a – The abbreviated weekday name (`Sun’)
%A – The full weekday name (`Sunday’)
%b – The abbreviated month name (`Jan’)
%B – The full month name (`January’)
%c – The preferred local date and time representation
%C – century number (the year divided by 100 and truncated to an integer, range 00 to 99)
%d – Day of the month (01..31)
%D – same as %m/%d/%y
%e – day of the month as a decimal number, a single digit is preceded by a space (range ‘1′ to ‘31′)
%g – like %G, but without the century.
%G – The 4-digit year corresponding to the ISO week number (see %V). This has the same format and value as %Y, except that if the ISO week number to the previous or next year, that year is used instead.
%h – same as %b
%H – Hour of the day, 24-hour clock (00..23)
%I – Hour of the day, 12-hour clock (01..12)
%j – Day of the year (001..366)
%m – Month of the year (01..12)
%M – Minute of the hour (00..59)
%n – newline character
%p – Meridian indicator (“AM” or “PM”)
%r – time in a.m. and p.m. notation
%R – time in 24 hour notation
%S – Second of the minute (00..60)
%t – tab character
%T – current time, equal to %H:%M:%S
%u – weekday as a decimal number [1,7], with 1 representing Monday
%U – Week number of the current year, starting with the first Sunday as the first day of the first week (00..53)
%V – The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week. (Use %G or %g for the year component that corresponds to the week number for the specified timestamp.)
%W – Week number of the current year, starting with the first Monday as the first day of the first week (00..53)
%w – Day of the week (Sunday is 0, 0..6)
%x – Preferred representation for the date alone, no time
%X – Preferred representation for the time alone, no date
%y – Year without a century (00..99)
%Y – Year with century
%Z or %z – Time zone name
%% – Literal character %
To use these formatting strings use the strftime and strptime methods of the Date and Datetime classes.

![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_c.png?x-id=6523170b-5a71-4304-9944-89e1ae1fa886)
![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_c.png?x-id=ea37f010-ae5a-4346-8e32-6f506a22d4f6)