Browse Source

Add some calendar functions.

Vladimir N. Shilov 3 years ago
parent
commit
96d417d778
1 changed files with 50 additions and 0 deletions
  1. 50 0
      clendar.c

+ 50 - 0
clendar.c

@@ -0,0 +1,50 @@
+/**
+  * https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%92%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%BA%D0%B0%D0%BB%D0%B5%D0%BD%D0%B4%D0%B0%D1%80%D1%8C#C,_C++
+  * получения дня недели из даты
+  * 0 - вск, 1-6 - пнд-сбт.
+  */
+
+typedef unsigned short Year;
+typedef unsigned char Month;
+typedef unsigned char Day;
+typedef unsigned char Weekday;
+const char* weekdays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+
+Weekday weekday(Year year, Month month, Day day) {
+	if (month < 3u) {
+		--year;
+		month += 10u;
+	} else
+		month -= 2u;
+	return (Weekday)((day + 31u * month / 12u + year + year / 4u - year / 100u + year / 400u) % 7u);
+}
+
+/**
+  * https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
+  * Optimizing UTC → Unix Time Conversion For Size And Speed
+  */
+
+/* https://github.com/protocolbuffers/upb/blob/22182e6e/upb/json/parser.rl#L1697
+ * epoch_days(1970, 1, 1) == 1970-01-01 == 0 */
+int epoch_days_table(int year, int month, int day) {
+  static const uint16_t month_yday[12] = {0,   31,  59,  90,  120, 151,
+                                          181, 212, 243, 273, 304, 334};
+  uint32_t year_adj = year + 4800;  /* Ensure positive year, multiple of 400. */
+  uint32_t febs = year_adj - (month <= 2 ? 1 : 0);  /* Februaries since base. */
+  uint32_t leap_days = 1 + (febs / 4) - (febs / 100) + (febs / 400);
+  uint32_t days = 365 * year_adj + leap_days + month_yday[month - 1] + day - 1;
+  return days - 2472692;  /* Adjust to Unix epoch. */
+}
+
+/* https://github.com/protocolbuffers/upb/blob/22182e6e/upb/json_decode.c#L982
+ * epoch_days_fast(1970, 1, 1) == 1970-01-01 == 0. */
+int epoch_days_fast(int y, int m, int d) {
+  const uint32_t year_base = 4800;    /* Before min year, multiple of 400. */
+  const uint32_t m_adj = m - 3;       /* March-based month. */
+  const uint32_t carry = m_adj > m ? 1 : 0;
+  const uint32_t adjust = carry ? 12 : 0;
+  const uint32_t y_adj = y + year_base - carry;
+  const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048;
+  const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400;
+  return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632;
+}