Click here to Skip to main content
15,064,351 members
Please Sign up or sign in to vote.
3.80/5 (5 votes)
See more:
How can I find the week number of a given date


Example :

1/1/2010 - 1 week

22/2/2010 - 9 week


like this ?????
Posted
Updated 14-May-13 20:22pm
v3

The week number comes from the %W spec. For example:

CString sDir = COleDateTime::GetCurrentTime().Format( "\\%Y\\%W" );


[without looking] I think you will get further information if you look at the help for strftime().
   
Comments
SoMad 14-May-13 1:55am
   
It looks like you nailed it :)
http://msdn.microsoft.com/en-us/library/vstudio/fe06s4ak.aspx[^]

Soren Madsen
Ian A Davidson 14-May-13 21:24pm
   
Seems a good solution if wanting a string. Would go with strftime rather than COleDateTime, unless the necessary dlls, etc, are already loaded and initialised.
However, I note it does not deal with many of the edge cases - namely first and last weeks of the year, returning 0 and 53 in many cases where it should return 52 or 53 and 1 respectively.
Ian.
Ian A Davidson 15-May-13 4:04am
   
Up'd to 5.
This is a good solution, provided that you are happy with the way the week number is calculated: being based on Monday as the first day of the week and the first week of the year being the first one which starts on Monday, (and the return value being a string).

Note that this means you will have week of year values from 0 to 53. And you can't simply add one to the week, since when the year starts on Monday it will already be week one, so you'd make it week two.

You can do the same calculation as strftime (COleDateTime) does by using this formula:

int week = ((yearDay + 8 - weekDay) / 7);
(Where yearDay = 0 to 365 and weekDay = 1 to 7; Monday = 1)

Regards,
Ian.
Of course, looking at my WHS diary, I realised that the first of January is not always in week 1, but is sometimes week 52/53 of the previous year, and also the last few days of December may be counted as the first week in the next year.

Thus all the solutions given so far, while some of them (including my own) will give a week number based on 1st Jan, they will not calculate the week of the year used as standard.

Also, it seems weeks do officially run from Monday to Sunday (even though we all know that Sunday is the first day of the week!)

A quick Google found this ISO Standard[^]. This says that week one of any year starts on the Monday before the first Thursday of the year. Or in other words, week one is the week in which the 4th of January falls (Monday to Sunday).

The initial calculation is similar to my first solution, but instead of adding 7, add 10 (and we have to adjust wday to 7 if it is 0 for Sunday).

Then if this calculation returns 0 the day is part of the last week of the preceding year. If it returns 53 we have to determine if it is part of week 1 of the next year, or if the year really does have 53 weeks (there are 71 in every 400 years - 5, 6 or 7 years apart).

Anyway, without further ado, here is my code for calculating this ISO week of the year:

C++
int GetWeek
	(
	struct tm* date
	)
{
	if (NULL == date)
	{
		return 0; // or -1 or throw exception
	}
	if (::mktime(date) < 0) // Make sure _USE_32BIT_TIME_T is NOT defined.
	{
		return 0; // or -1 or throw exception
	}
	// The basic calculation:
	// {Day of Year (1 to 366) + 10 - Day of Week (Mon = 1 to Sun = 7)} / 7
	int monToSun = (date->tm_wday == 0) ? 7 : date->tm_wday; // Adjust zero indexed week day
	int week = ((date->tm_yday + 11 - monToSun) / 7); // Add 11 because yday is 0 to 365.

	// Now deal with special cases:
	// A) If calculated week is zero, then it is part of the last week of the previous year.
	if (week == 0)
	{
		// We need to find out if there are 53 weeks in previous year.
		// Unfortunately to do so we have to call mktime again to get the information we require.
		// Here we can use a slight cheat - reuse this function!
		// (This won't end up in a loop, because there's no way week will be zero again with these values).
		tm lastDay = { 0 };
		lastDay.tm_mday = 31;
		lastDay.tm_mon = 11;
		lastDay.tm_year = date->tm_year - 1;
		// We set time to sometime during the day (midday seems to make sense)
		// so that we don't get problems with daylight saving time.
		lastDay.tm_hour = 12;
		week = GetWeek(&lastDay);
	}
	// B) If calculated week is 53, then we need to determine if there really are 53 weeks in current year
	//    or if this is actually week one of the next year.
	else if (week == 53)
	{
		// We need to find out if there really are 53 weeks in this year,
		// There must be 53 weeks in the year if:
		// a) it ends on Thurs (year also starts on Thurs, or Wed on leap year).
		// b) it ends on Friday and starts on Thurs (a leap year).
		// In order not to call mktime again, we can work this out from what we already know!
		int lastDay = date->tm_wday + 31 - date->tm_mday;
		if (lastDay == 5) // Last day of the year is Friday
		{
			// How many days in the year?
			int daysInYear = date->tm_yday + 32 - date->tm_mday; // add 32 because yday is 0 to 365
			if (daysInYear < 366)
			{
				// If 365 days in year, then the year started on Friday
				// so there are only 52 weeks, and this is week one of next year.
				week = 1;
			}
		}
		else if (lastDay != 4) // Last day is NOT Thursday
		{
			// This must be the first week of next year
			week = 1;
		}
		// Otherwise we really have 53 weeks!
	}
	return week;
}

int GetWeek
	(          // Valid values:
	int day,   // 1 to 31
	int month, // 1 to 12.  1 = Jan.
	int year   // 1970 to 3000
	)
{
	tm date = { 0 };
	date.tm_mday = day;
	date.tm_mon = month - 1;
	date.tm_year = year - 1900;
	// We set time to sometime during the day (midday seems to make sense)
	// so that we don't get problems with daylight saving time.
	date.tm_hour = 12;
	return GetWeek(&date);
}


Example usage:

C++
int week = GetWeek(15,5,2013);


C++
int GetCurrentWeek()
{
	tm today;
	time_t now;
	time(&now);
	errno_t error = ::localtime_s(&today, &now);
	return GetWeek(&today);
}


All the best.

Regards,
Ian.
   
v2
Comments
SoMad 14-May-13 21:31pm
   
Are you sure this is necessary? I have not tested out Solution 1 to verify it always works correctly, but I would think that it does, including taking the locale into account. Things like which is the first day of the week is a locale setting and changes how the Windows calendar controls are laid out.

Soren Madsen
Ian A Davidson 14-May-13 22:08pm
   
Well, I ran a few dates from beginning of Jan and End of Dec through it for years between 1997 and 2015. Try it yourself and see what you get. Looking through all the years, when it returns 0, the "standard" week is actually 1, or 52 or 53 of the previous year. Sometimes when it returns 52 or 53 it should be week 1 of the next year. Some years the week number is out by 1 for the entire year, and sometimes it is largely correct, except for the few days at the beginning and/or end.
So it looks like it would still need some adjustment, though it is less clear what.
But anyway, I've enjoyed looking into this tonight - didn't realise such a simple question could have so many controversies (have you looked at the Wikipedia discussion page?). The basic calculation (week from beginning of the year) is straight forward.
I realise fitting in with Windows' locale options is important :) If you find a function that does it correctly, or some setting perhaps that sorts strftime out, by all means share it.
Regards,
Ian.
Ian A Davidson 14-May-13 22:40pm
   
Actually (sadly gripped by this aren't I!) I've just looked again at strftime definition for %W and it says "Week of year as decimal number, with Monday as first day of week (00 – 53)". So it would appear it doesn't take the locale into account.
I can also see now that it takes the first week of the year being from the first Monday in the year.
Therefore this calculation provides identical results (week resulting as 0 to 53):
int week = ((date.tm_yday + 8 - monToSun) / 7);
(Where date.tm_yday = 0 to 365 and monToSun is the week day, 1 to 7; Monday = 1)

You could replace that in my code above, but I'm not going to spend more time working out how to do the adjustment for that, as I believe my code is providing the ISO standard answer, matching what is presented in my diaries!

Regards,
Ian.
SoMad 14-May-13 23:56pm
   
Yes, I saw the definition for %W said Monday as first day of week, but that matches your ISO definition in the Wiki link. This actually explains to me why hardly any Americans know about week numbers at all, while back in Denmark (where Monday is the first day of the week) they are printed on just about every single calendar.
I remember back in 1998, the calendars we had at the office in Denmark had messed things up and showed the last two weeks as 52, 52 instead of 52, 53. It was pretty funny.

Hmmm...wait a second, there is a blurb towards the bottom of your Wiki page about how the US week numbering system follows the Sunday to Saturday scheme and uses partial weeks at the beginning and end of the year.

Soren Madsen
Ian A Davidson 15-May-13 3:51am
   
Yes, Monday is the first day of the week in both, but the difference is that the ISO standard (note it's not "my" ISO definition - ISO is the International Standards Organisation!) defines the first week of the year as the week with the first Thursday, whereas the strftime function makes the first Monday the beginning of the first week.

The strftime function, as you point out, also doesn't adjust the partial weeks at the start and end. Note that although it's not been marked as the answer, this solution I've provided is the ONLY one given so far which does give the standard week numbers.

Who'd have thought such a simple question could have so many possibilities? :)

Cheers,
Ian.
SoMad 15-May-13 4:06am
   
Yes, I know it's not your definition, I know what ISO is.
I saw your comment about strftime making the first Monday of the year the beginning of the first week. Did you determine this by throwing dates at it or did you find that documented somewhere?

Soren Madsen
Ian A Davidson 15-May-13 4:10am
   
Throwing dates at it: a few dates from each of the beginning of Jan and the end of Dec, for all the years between 1997 and 2015. :)
The same problem you can solve by Boost,
for example see following code:
C++
#include <iostream>
#include <boost/date_time/gregorian/gregorian.hpp>

using namespace std;
using namespace boost::gregorian;

int main()
{
 date_duration dd = date(2000, 1, 1) - date(1900, 1, 1);
 date_duration dd1(7);
 dd = date(2100, 1, 1) - date(2000, 1, 1);
 dd = (dd.days() < 7) ? dd1 : dd; 
 int number_of_weeks = (0==(dd.days()%7)) ? dd.days()/7 : (dd.days()/7 + 1);
 cout << "The number of weeks between two dates is" << number_of_weeks << endl;
}
   
v4
Comments
Ian A Davidson 14-May-13 21:18pm
   
This doesn't seem to be at all what was asked for.
Volynsky Alex 15-May-13 1:55am
   
Why?
It is necessary to specify the distance between the two dates, for example, between:
1/1/2010 and 22/2/2010, calculate the number of days between them, and then divide the result by 7 ....
Ian A Davidson 15-May-13 4:08am
   
He asked for the week number in the year. Even if you'd specified the same year in your calculation, this answer as well as the other one doesn't take into account which day is the first day of the year - so a week here may be defined as Monday to Sunday one year, Tuesday to Monday another year, Wednesday to Tuesday another year, etc, etc.
Regards,
Ian.
Volynsky Alex 15-May-13 6:00am
   
Ok, I take into account what you're talking about
Please, look following line:
dd = (dd.days() < 7) ? dd1 : dd;
Regards,
Alex.
Ian A Davidson 15-May-13 11:55am
   
Yes, I think that actually introduces an error. If number of days is less than 7 the result will be 1, because it is forced to 7 and 7/7 = 1. But if the number of days is 8 to 13 inclusive, the result will also be 1 because the integral value of 8/7 = 13/7 = 1. So there are now two weeks that are week 1.
Regards,
Ian.
To implement this task, you could use the following code:
C++
#include <ctime>
#include <iostream>
#include <cstdlib>

using namespace std;

time_t dateToTimeT(int month, int day, int year) 
{
 tm tmp = tm();
 tmp.tm_mday = day;
 tmp.tm_mon = month - 1;
 tmp.tm_year = year - 1900;

 return mktime(&tmp);
}

time_t badTime() 
{
 return time_t(-1);
}

time_t now() 
{
 return time(0);
}

int main() 
{
 time_t date1 = dateToTimeT(1,1,2000);
 time_t date2 = dateToTimeT(1,1,2001);

 if ((date1 == badTime()) || (date2 == badTime())) 
 {
   cerr << "impossible to create a structure time_t" << endl;
   return EXIT_FAILURE;
 }

 double sec = difftime(date2, date1);

 long days = static_cast<long>(sec / (60 * 6024));
 long number_of_weeks = days / 7;
 cout << The number of weeks between 1 January 2000 and 1 January 2001 is ";

 cout << number_of_weeks << endl;

 return EXIT_SUCCESS;

}
   
v2
Comments
Ian A Davidson 14-May-13 5:13am
   
There's really no need to go to the trouble of taking difference between the date and the first of January. Once you've called mktime, the tm structure you passed will have been completed to contain the day of year and the week day, so you only need to call it once for the date you are interested in and then calculate based on that. See my solution :)
Regards,
Ian.
Volynsky Alex 15-May-13 2:03am
   
There are different solutions for one same problem....
I think that the questioner can choose the most appropriate answer for him
Ian A Davidson 15-May-13 3:58am
   
True. I was just saying that since you've used mktime once you can calculate the week without having to call it again and work out a "difference" - you already have that information (except, if you want to adjust the partial weeks correctly, there are a few cases where you would have to call it again). As we have determined, you can do exactly the same calculation as strftime does by doing this: int week = ((date.tm_yday + 8 - monToSun) / 7); Besides which, I've just realised your answer is actually incorrect as it determines the week number based on whatever day of the week is the 1st of Jan. I.e. if 1st Jan is a Wednesday, then weeks will be from Wed to Tues. I.e. Wed 1 Jan to Tues 7th Jan is week 1; Wed 8th Jan to Tues 14th Jan is week 2; etc. Regards, Ian.
Volynsky Alex 15-May-13 5:25am
   
Anyway Ian A Davidson , my answer is correct, but unfortunately you're just don't understand it well enough.
Don't forget asked question: "How can I find the week number of a given date"...
Therefore, if we want to calculate how many weeks have passed since the New Year, then user just should to do following things:
time_t date1 = dateToTimeT(1,1,2013);
time_t date2 = dateToTimeT(<today's date>); //given date...
In addition, I believe that my answer in general is more understandable for users
Regards,
Alex.
Ian A Davidson 15-May-13 7:04am
   
Sorry if I am misunderstanding you. I agree that the question was "How can I find the week number of a given date?" The title is "Help to find out the Week number of year?" So the question I would put to you is, "what does a year's week number mean to you?" To me it means the number of the week of any year where each week starts on a fixed day (e.g. Sunday or Monday). The solution you have proposed assumes each week number is based on the day on which the YEAR starts. I.e. for a year where 1st Jan is Wednesday, even allowing for the typo in your code (I think you mean "60 * 60 * 24", not "60 * 60 - 24"), in your solution Monday 13th Jan (for example) would fall in week 2 (it would in fact return 1, since it is zero-indexed; which is fair enough): int((13 - 1) / 7) = 1 (+1 = week 2) - where the weeks are Wed 1st-Tues 7th; Wed 8th-Tues 14th. The standard answer in this case, however, should be week 3! Week 1 is: Wed 1st-Sun 5th; Week 2: Mon 6th-Sun 12th; Week 3: Mon 13th-Sun 19th. (OR, if starting on Sunday: Wed 1st-Sat 4th; Sun 5th-Sat 11th; Sun 12th-Sat 18th). I hope this helps. Regards, Ian.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900