[英]Find the date given the year, the month and the “nth” occurrance of day within the month C/C++
In order that a device (with limited memory) is able to manage its own timezone and daylight savings, I'm trying to calculate daylight savings triggers for 85 time zones based on a simplified description of each timezone. 为了使设备(内存有限)能够管理自己的时区和夏时制,我尝试根据每个时区的简化描述来计算85个时区的夏时制触发器。 I have access to minimal C and C++ libraries within the device.
我可以访问设备中的最小C和C ++库。 The format of the timezone (inc. DST) description for each time zone is as follows:
每个时区的时区描述格式(包括DST)如下:
I have found numerous examples going the other way, ie starting with the date, but they involve using the modulus, keeping the remainder and dropping the quotient hence I have been unable to transpose the formula to suit my needs. 我发现无数示例都从日期开始,但是它们涉及使用模数,保留余数并减去商,因此我无法调换公式以满足我的需要。
I also tried to reuse the standard "Jan = 6, Feb = 2, Mar = 2, Apr = 5, May = 0, etc. modifier table and year modifiers from the "tell me what day the 25th of June, 2067 is?" party trick and developed the following algorithm. 我还尝试重复使用标准“ 1月= 6、2月= 2、3月= 2、4月= 5、5月= 0,依此类推。”的修饰符表和年份修饰符来自“告诉我2067年6月25日是哪一天?方技巧并开发了以下算法。
Date = DayOfWeek + ((NthOccuranceOfDay - 1) x 7 ) - MonthCode - YearCode
This worked for the first 6 random test dates I selected but then I started to see dates for which it failed. 这对我选择的前6个随机测试日期有效,但随后我开始查看失败的日期。 Is it possible that the basic algorithm is sound but I'm missing a further modifier or maybe that I'm applying the modifiers incorrectly?
基本算法是否合理,但是我缺少进一步的修饰符,或者我错误地应用了修饰符,这可能吗?
Is there another solution I could utilize? 有没有我可以利用的其他解决方案?
Using this open source, cross platform date library , one can write: 使用这种开源的跨平台日期库 ,可以编写:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
year_month_day us_daylight_starts = sys_days(sun[2]/mar/2015);
year_month_day us_daylight_ends = sys_days(sun[1]/nov/2015);
std::cout << us_daylight_starts << '\n';
std::cout << us_daylight_ends << '\n';
}
which will output: 将输出:
2015-03-08
2015-11-01
The formulas this library is based on are in the public domain and documented here . 该库所基于的公式在公共领域中,并在此处进行记录 。
The algorithms paper has very complete unit tests validating the date algorithms over a range of millions of years (a far larger range than is necessary). 该算法文件具有非常完整的单元测试,可在数百万年的范围内验证日期算法(远远超出了必需的范围)。
Sometimes daylight savings rules are written in terms of the last weekday of a month. 有时,夏令时规则是按照一个月的最后一个工作日来编写的。 That is just as easily handled:
这同样容易处理:
year_month_day ymd = sys_days(sun[last]/nov/2015);
std::cout << ymd << '\n'; // 2015-11-29
That formula will be off by one week (or even two weeks) if MonthCode
+ YearCode
is greater than or equal to DayOfWeek
, because in that case you will be counting NthOccurenceOfDay
from a negative date. 如果
MonthCode
+ YearCode
大于或等于DayOfWeek
,则该公式将MonthCode
一周(甚至两周)的时间,因为在这种情况下,您将从否定日期开始计算NthOccurenceOfDay
。
As an alternative, with no tables, you can compute the day of week of the first of the month using, for example, Zeller's algorithm : 作为替代方案,没有表格,您可以使用例如Zeller算法计算每月第一天的星期几:
int NthOccurrence(int year, int month, int n, int dayOfWeek) {
// year is the current year (eg. 2015)
// month is the target month (January == 1...December == 12)
// Finds the date of the nth dayOfWeek (Sun == 0...Sat == 6)
// Adjust month and year
if (month < 3) { --year, month += 12; }
// The gregorian calendar is a 400-year cycle
year = year % 400;
// There are no leap years in years 100, 200 and 300 of the cycle.
int century = year / 100;
int leaps = year / 4 - century;
// A normal year is 52 weeks and 1 day, so the calendar advances one day.
// In a leap year, it advances two days.
int advances = year + leaps;
// This is either magic or carefully contrived,
// depending on how you look at it:
int month_offset = (13 * (month + 1)) / 5;
// From which, we can compute the day of week of the first of the month:
int first = (month_offset + advances) % 7;
// If the dayOfWeek we're looking for is at least the day we just
// computed, we just add the difference. Otherwise, we need to add 7.
// Then we just add the desired number of weeks.
int offset = dayOfWeek - first;
if (offset < 0) offset += 7;
return 1 + offset + (n - 1) * 7;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.