c – Semaine de l’année avec des jours de début et d’ancrage variables

Synopsis:

Je souhaite trouver le numéro de semaine d’une date donnée avec des jours de départ et d’ancrage variables pour la semaine.

Version complète:

Je dois calculer la semaine où un jour donné tombe sur une année, mais je dois pouvoir changer ce qui définit une semaine. Définir une semaine se résume à deux facteurs:

Le début et la fin de la semaine s’expliquent d’eux-mêmes. Il décidera simplement quel dimanche compter dans une semaine, le dimanche précédent ou le dimanche suivant (ou, si la date que nous regardons est un dimanche, décide à quelle semaine il appartient. ). Le jour d’ancrage déterminera le roulement de l’année. Supposons que mercredi soit en yr1 mais que le lendemain (jeudi) soit en yr2 :

  • Cas 1: le mercredi définit la semaine. Par conséquent, la partie suivante de la semaine fait également partie de l’année yr1 , de la semaine 52 (parfois 53 si l’année compte 53 jours d’ancrage).
  • Cas 2: jeudi définit la semaine et la partie précédente de la semaine est donc également en année yr2 , semaine 01 .

J’utilise un struct tm * pour capturer la date et l’heure que je souhaite convertir. J’ai donc beaucoup de données sur lesquelles travailler. Je ne sais tout simplement pas quelles manipulations effectuer pour calculer cela correctement. Je sais que la fonction strftime peut lancer un numéro de semaine 00-53 et peut même choisir le jour où la semaine commence entre dimanche et lundi, mais il n’y a aucun moyen de modifier le jour d’ancrage d’une semaine pour que le roulement d’année ne fonctionne pas. de cette façon.

Toutes les idées ou suggestions sont appréciées, car ce problème ne disparaîtra pas tout seul! Merci!

Edit: Le code permettant de capturer l’heure dans une struct tm * est:

 time_t time_stamp; struct tm *time_local; time(&time_stamp); // fills in the current time in seconds, GMT time_local = localtime(&time_stamp); // translates seconds GMT to tm in local time zone 

Les données qui entrent dans ces variables sont toutes correctes, la bonne date et heure, le fuseau horaire, etc.

Semaine de l’année avec des jours de départ et d’ancrage variables

Cette question est assez directe: recherchez la “semaine de l’année” et son “semaine de l’année” pour une année, un mois et un jour donnés.


Étape 1: Trouvez le DayOfTheWeek la DayOfTheWeek (0-6). mktime() prendra une struct tm et définira sa base de membres tm_yday (0-365) et tm_wday (0-6) sur les autres champs. Pour mktime() , la semaine commence le dimanche. Ajustez avec une valeur de 0 à 6 pour les autres modèles indiquant le début du jour de la semaine – cette partie est assez sortingviale . Assurez-vous que % 7 n’est pas appliqué aux nombres négatifs.

Étape 2, ajustez la date au début de la semaine avec .tm_mday -= DayOfTheWeek;

Étape 3, ajustez la date au milieu de semaine de la semaine en ajoutant 3. Astuce: le jour de milieu de semaine correspond toujours à la même année civile que l’année de la semaine.

Étape 4: Appelez mktime() pour réinitialiser les membres .tm.tm_year et .tm_yday . Divisez .tm_yday par 7 pour obtenir la semaine de l’année (et ajoutez 1 car la première semaine correspond à la semaine 1 et non à 0).

L’appel de mktime() deux resockets gère correctement tous les cas, comme indiqué ci-dessous.

 #include  #include  // return 1 on failure, 0 on success int tm_YearWeek(int y, int m, int d, int FirstDOW, int *year, int *week) { // Set to noon to avoid DST issues. struct tm tm = { .tm_year = y - 1900, .tm_mon = m - 1, .tm_mday = d, .tm_hour = 12}; // Calculate tm_wday. if (mktime(&tm) == -1) { return 1; } // Find day-of-the-week: 0 to 6. // Week starts on Monday per ISO 8601 // 0 <= DayOfTheWeek <= 6, (Monday, Tuesday ... Sunday) int DayOfTheWeek = (tm.tm_wday + (7 - 1) - FirstDOW%7) % 7; // Offset the month day to the 1st day of the week (Monday). // This may make tm.tm_mday <= 0 or > EndOfMonth tm.tm_mday -= DayOfTheWeek; // Offset the month day to the mid-week (Thursday) // tm.tm_mday <= 0 or > EndOfMonth may be true tm.tm_mday += 3; // Re-evaluate tm_year and tm_yday (local time) if (mktime(&tm) == -1) { return 1; } *year = tm.tm_year + 1900; // Convert yday to week of the year, stating with 1. //printf("doy %4d %4d\n", tm.tm_yday, tm.tm_yday/7 + 1); *week = tm.tm_yday / 7 + 1; return 0; } 

Un code de test

 #define FirstDOW_Monday 0 #define FirstDOW_Sunday 6 const char *FirstDOW_Ddd[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; void TestHarness_YearWeek(int y, int m, int d, int FirstDOW) { int ywd_year, ywd_week; int e = tm_YearWeek(y,m,d, FirstDOW, &ywd_year, &ywd_week); if (e) { fprintf(stderr, "Fail\n"); exit(EXIT_FAILURE); } struct tm tm = { .tm_year = y - 1900, .tm_mon = m - 1, .tm_mday = d, .tm_hour = 12}; mktime(&tm); printf("%s %4d-%2d-%2d --> Year/Week %04d-W%02d (week starts: %s)\n", FirstDOW_Ddd[(tm.tm_wday + 6) % 7], y, m, d, ywd_year, ywd_week, FirstDOW_Ddd[FirstDOW]); } void TestHarness_2012(int year, int FirstDOW) { printf(" Jan %d\n", year); puts(" SMTWTFS"); if (year == 2014) puts(" 1 2 3 4"); if (year == 2015) puts(" 1 2 3"); for (int i = 28; i <= 31; i++) TestHarness_YearWeek(year-1, 12, i, FirstDOW); for (int i = 1; i <= 6; i++) TestHarness_YearWeek(year, 1, i, FirstDOW); puts(""); } 

Sortie

  Jan 2014 SMTWTFS 1 2 3 4 Sat 2013-12-28 --> Year/Week 2013-W52 (week starts: Mon) Sun 2013-12-29 --> Year/Week 2013-W52 (week starts: Mon) Mon 2013-12-30 --> Year/Week 2014-W01 (week starts: Mon)1st 2014 week start:Dec 30,2013 Tue 2013-12-31 --> Year/Week 2014-W01 (week starts: Mon) Wed 2014- 1- 1 --> Year/Week 2014-W01 (week starts: Mon) Thu 2014- 1- 2 --> Year/Week 2014-W01 (week starts: Mon) Fri 2014- 1- 3 --> Year/Week 2014-W01 (week starts: Mon) Sat 2014- 1- 4 --> Year/Week 2014-W01 (week starts: Mon) Sun 2014- 1- 5 --> Year/Week 2014-W01 (week starts: Mon) Mon 2014- 1- 6 --> Year/Week 2014-W02 (week starts: Mon) Jan 2014 SMTWTFS 1 2 3 4 Sat 2013-12-28 --> Year/Week 2013-W52 (week starts: Sun) Sun 2013-12-29 --> Year/Week 2014-W01 (week starts: Sun)1st 2014 week start:Dec 29,2013 Mon 2013-12-30 --> Year/Week 2014-W01 (week starts: Sun) Tue 2013-12-31 --> Year/Week 2014-W01 (week starts: Sun) Wed 2014- 1- 1 --> Year/Week 2014-W01 (week starts: Sun) Thu 2014- 1- 2 --> Year/Week 2014-W01 (week starts: Sun) Fri 2014- 1- 3 --> Year/Week 2014-W01 (week starts: Sun) Sat 2014- 1- 4 --> Year/Week 2014-W01 (week starts: Sun) Sun 2014- 1- 5 --> Year/Week 2014-W02 (week starts: Sun) Mon 2014- 1- 6 --> Year/Week 2014-W02 (week starts: Sun) Jan 2015 SMTWTFS 1 2 3 Sun 2014-12-28 --> Year/Week 2014-W52 (week starts: Mon) Mon 2014-12-29 --> Year/Week 2015-W01 (week starts: Mon)1st 2015 week start:Dec 29,2014 Tue 2014-12-30 --> Year/Week 2015-W01 (week starts: Mon) Wed 2014-12-31 --> Year/Week 2015-W01 (week starts: Mon) Thu 2015- 1- 1 --> Year/Week 2015-W01 (week starts: Mon) Fri 2015- 1- 2 --> Year/Week 2015-W01 (week starts: Mon) Sat 2015- 1- 3 --> Year/Week 2015-W01 (week starts: Mon) Sun 2015- 1- 4 --> Year/Week 2015-W01 (week starts: Mon) Mon 2015- 1- 5 --> Year/Week 2015-W02 (week starts: Mon) Tue 2015- 1- 6 --> Year/Week 2015-W02 (week starts: Mon) Jan 2015 SMTWTFS 1 2 3 Sun 2014-12-28 --> Year/Week 2014-W53 (week starts: Sun) Mon 2014-12-29 --> Year/Week 2014-W53 (week starts: Sun) Tue 2014-12-30 --> Year/Week 2014-W53 (week starts: Sun) Wed 2014-12-31 --> Year/Week 2014-W53 (week starts: Sun) Thu 2015- 1- 1 --> Year/Week 2014-W53 (week starts: Sun) Fri 2015- 1- 2 --> Year/Week 2014-W53 (week starts: Sun) Sat 2015- 1- 3 --> Year/Week 2014-W53 (week starts: Sun) Sun 2015- 1- 4 --> Year/Week 2015-W01 (week starts: Sun)1st 2015 week start:Jan 1, 2016 Mon 2015- 1- 5 --> Year/Week 2015-W01 (week starts: Sun) Tue 2015- 1- 6 --> Year/Week 2015-W01 (week starts: Sun)