PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/time.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 683 lines | 543 code | 96 blank | 44 comment | 130 complexity | 54ed786b9c6612c43026277b19721131 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if SILVERLIGHT && CLR2
  16. extern alias systemcore;
  17. using TimeZoneInfo = systemcore::System.TimeZoneInfo;
  18. #endif
  19. using System;
  20. using System.Collections;
  21. using System.Collections.Generic;
  22. using System.Diagnostics;
  23. using System.Globalization;
  24. using System.Runtime.CompilerServices;
  25. using System.Text;
  26. using System.Threading;
  27. using Microsoft.Scripting;
  28. using Microsoft.Scripting.Runtime;
  29. using Microsoft.Scripting.Utils;
  30. using IronPython.Runtime;
  31. using IronPython.Runtime.Operations;
  32. using IronPython.Runtime.Types;
  33. [assembly: PythonModule("time", typeof(IronPython.Modules.PythonTime))]
  34. namespace IronPython.Modules {
  35. public static class PythonTime {
  36. private const int YearIndex = 0;
  37. private const int MonthIndex = 1;
  38. private const int DayIndex = 2;
  39. private const int HourIndex = 3;
  40. private const int MinuteIndex = 4;
  41. private const int SecondIndex = 5;
  42. private const int WeekdayIndex = 6;
  43. private const int DayOfYearIndex = 7;
  44. private const int IsDaylightSavingsIndex = 8;
  45. private const int MaxIndex = 9;
  46. private const int minYear = 1900; // minimum year for python dates (CLS dates are bigger)
  47. private const double epochDifference = 62135596800.0; // Difference between CLS epoch and UNIX epoch, == System.DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc).Ticks / TimeSpan.TicksPerSecond
  48. private const double ticksPerSecond = (double)TimeSpan.TicksPerSecond;
  49. public static readonly int altzone;
  50. public static readonly int daylight;
  51. public static readonly int timezone;
  52. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  53. public static readonly PythonTuple tzname;
  54. public const bool accept2dyear = true;
  55. #if !SILVERLIGHT // System.Diagnostics.Stopwatch
  56. [MultiRuntimeAware]
  57. private static Stopwatch sw;
  58. #endif
  59. public const string __doc__ = "This module provides various functions to manipulate time values.";
  60. [SpecialName]
  61. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  62. // we depend on locale, it needs to be initialized
  63. PythonLocale.EnsureLocaleInitialized(context);
  64. }
  65. static PythonTime() {
  66. // altzone, timezone are offsets from UTC in seconds, so they always fit in the
  67. // -13*3600 to 13*3600 range and are safe to cast to ints
  68. #if !SILVERLIGHT
  69. DaylightTime dayTime = TimeZone.CurrentTimeZone.GetDaylightChanges(DateTime.Now.Year);
  70. daylight = (dayTime.Start == dayTime.End && dayTime.Start == DateTime.MinValue && dayTime.Delta.Ticks == 0) ? 0 : 1;
  71. tzname = PythonTuple.MakeTuple(TimeZone.CurrentTimeZone.StandardName, TimeZone.CurrentTimeZone.DaylightName);
  72. altzone = (int)-TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).TotalSeconds;
  73. timezone = altzone;
  74. if (daylight != 0) {
  75. // GetUtcOffset includes adjustments for timezones. If we're in daylight saving time then
  76. // we need to adjust timezone so it is the correct time. Otherwise we need to adjust altzone
  77. if (TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now)) {
  78. timezone += (int)dayTime.Delta.TotalSeconds;
  79. } else {
  80. altzone -= (int)dayTime.Delta.TotalSeconds;
  81. }
  82. }
  83. #else
  84. daylight = TimeZoneInfo.Local.SupportsDaylightSavingTime ? 1 : 0;
  85. tzname = PythonTuple.MakeTuple(TimeZoneInfo.Local.StandardName, TimeZoneInfo.Local.DaylightName);
  86. timezone = (int)-TimeZoneInfo.Local.BaseUtcOffset.TotalSeconds;
  87. altzone = (int)-TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).TotalSeconds;
  88. #endif
  89. }
  90. internal static long TimestampToTicks(double seconds) {
  91. return (long)((seconds + epochDifference) * ticksPerSecond);
  92. }
  93. internal static double TicksToTimestamp(long ticks) {
  94. return (ticks / ticksPerSecond) - epochDifference;
  95. }
  96. public static string asctime(CodeContext/*!*/ context) {
  97. return asctime(context, null);
  98. }
  99. public static string asctime(CodeContext/*!*/ context, object time) {
  100. DateTime dt;
  101. if (time is PythonTuple) {
  102. // docs say locale information is not used by asctime, so ignore DST here
  103. dt = GetDateTimeFromTupleNoDst(context, (PythonTuple)time);
  104. } else if (time == null) {
  105. dt = DateTime.Now;
  106. } else {
  107. throw PythonOps.TypeError("expected struct_time or None");
  108. }
  109. return dt.ToString("ddd MMM dd HH:mm:ss yyyy", null);
  110. }
  111. public static double clock() {
  112. #if !SILVERLIGHT // System.Diagnostics.Stopwatch
  113. InitStopWatch();
  114. return ((double)sw.ElapsedTicks) / Stopwatch.Frequency;
  115. #else
  116. return (double)DateTime.Now.Ticks / (double)TimeSpan.TicksPerSecond;
  117. #endif
  118. }
  119. public static string ctime(CodeContext/*!*/ context) {
  120. return asctime(context, localtime());
  121. }
  122. public static string ctime(CodeContext/*!*/ context, object seconds) {
  123. if (seconds == null)
  124. return ctime(context);
  125. return asctime(context, localtime(seconds));
  126. }
  127. public static void sleep(double tm) {
  128. Thread.Sleep((int)(tm * 1000));
  129. }
  130. public static double time() {
  131. return TicksToTimestamp(DateTime.Now.ToUniversalTime().Ticks);
  132. }
  133. public static PythonTuple localtime() {
  134. return GetDateTimeTuple(DateTime.Now, DateTime.Now.IsDaylightSavingTime());
  135. }
  136. public static PythonTuple localtime(object seconds) {
  137. if (seconds == null) return localtime();
  138. DateTime dt = TimestampToDateTime(GetTimestampFromObject(seconds));
  139. dt = dt.AddSeconds(-timezone);
  140. return GetDateTimeTuple(dt, dt.IsDaylightSavingTime());
  141. }
  142. public static PythonTuple gmtime() {
  143. return GetDateTimeTuple(DateTime.Now.ToUniversalTime(), false);
  144. }
  145. public static PythonTuple gmtime(object seconds) {
  146. if (seconds == null) return gmtime();
  147. DateTime dt = new DateTime(TimestampToTicks(GetTimestampFromObject(seconds)), DateTimeKind.Unspecified);
  148. return GetDateTimeTuple(dt, false);
  149. }
  150. public static double mktime(CodeContext/*!*/ context, PythonTuple localTime) {
  151. return TicksToTimestamp(GetDateTimeFromTuple(context, localTime).AddSeconds(timezone).Ticks);
  152. }
  153. public static string strftime(CodeContext/*!*/ context, string format) {
  154. return strftime(context, format, DateTime.Now, null);
  155. }
  156. public static string strftime(CodeContext/*!*/ context, string format, PythonTuple dateTime) {
  157. return strftime(context, format, GetDateTimeFromTupleNoDst(context, dateTime), null);
  158. }
  159. public static object strptime(CodeContext/*!*/ context, string @string) {
  160. return DateTime.Parse(@string, PythonLocale.GetLocaleInfo(context).Time.DateTimeFormat);
  161. }
  162. public static object strptime(CodeContext/*!*/ context, string @string, string format) {
  163. bool postProc;
  164. FoundDateComponents foundDateComp;
  165. List<FormatInfo> formatInfo = PythonFormatToCLIFormat(format, true, out postProc, out foundDateComp);
  166. DateTime res;
  167. if (postProc) {
  168. int doyIndex = FindFormat(formatInfo, "\\%j");
  169. int dowMIndex = FindFormat(formatInfo, "\\%W");
  170. int dowSIndex = FindFormat(formatInfo, "\\%U");
  171. if (doyIndex != -1 && dowMIndex == -1 && dowSIndex == -1) {
  172. res = new DateTime(1900, 1, 1);
  173. res = res.AddDays(Int32.Parse(@string));
  174. } else if (dowMIndex != -1 && doyIndex == -1 && dowSIndex == -1) {
  175. res = new DateTime(1900, 1, 1);
  176. res = res.AddDays(Int32.Parse(@string) * 7);
  177. } else if (dowSIndex != -1 && doyIndex == -1 && dowMIndex == -1) {
  178. res = new DateTime(1900, 1, 1);
  179. res = res.AddDays(Int32.Parse(@string) * 7);
  180. } else {
  181. throw PythonOps.ValueError("cannot parse %j, %W, or %U w/ other values");
  182. }
  183. } else {
  184. string[] formats = new string[formatInfo.Count];
  185. for (int i = 0; i < formatInfo.Count; i++) {
  186. switch (formatInfo[i].Type) {
  187. case FormatInfoType.UserText: formats[i] = "'" + formatInfo[i].Text + "'"; break;
  188. case FormatInfoType.SimpleFormat: formats[i] = formatInfo[i].Text; break;
  189. case FormatInfoType.CustomFormat:
  190. // include % if we only have one specifier to mark that it's a custom
  191. // specifier
  192. if (formatInfo.Count == 1 && formatInfo[i].Text.Length == 1) {
  193. formats[i] = "%" + formatInfo[i].Text;
  194. } else {
  195. formats[i] = formatInfo[i].Text;
  196. }
  197. break;
  198. }
  199. }
  200. try {
  201. if (!StringUtils.TryParseDateTimeExact(@string,
  202. String.Join("", formats),
  203. PythonLocale.GetLocaleInfo(context).Time.DateTimeFormat,
  204. DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.NoCurrentDateDefault,
  205. out res)) {
  206. // If TryParseExact fails, fall back to DateTime.Parse which does a better job in some cases...
  207. res = DateTime.Parse(@string, PythonLocale.GetLocaleInfo(context).Time.DateTimeFormat);
  208. }
  209. } catch (FormatException e) {
  210. throw PythonOps.ValueError(e.Message + Environment.NewLine + "data=" + @string + ", fmt=" + format + ", to: " + String.Join("", formats));
  211. }
  212. }
  213. if ((foundDateComp & FoundDateComponents.Year) == 0) {
  214. res = new DateTime(1900, res.Month, res.Day, res.Hour, res.Minute, res.Second, res.Millisecond, res.Kind);
  215. }
  216. return GetDateTimeTuple(res);
  217. }
  218. internal static string strftime(CodeContext/*!*/ context, string format, DateTime dt, int? microseconds) {
  219. bool postProc;
  220. FoundDateComponents found;
  221. List<FormatInfo> formatInfo = PythonFormatToCLIFormat(format, false, out postProc, out found);
  222. StringBuilder res = new StringBuilder();
  223. for (int i = 0; i < formatInfo.Count; i++) {
  224. switch (formatInfo[i].Type) {
  225. case FormatInfoType.UserText: res.Append(formatInfo[i].Text); break;
  226. case FormatInfoType.SimpleFormat: res.Append(dt.ToString(formatInfo[i].Text, PythonLocale.GetLocaleInfo(context).Time.DateTimeFormat)); break;
  227. case FormatInfoType.CustomFormat:
  228. // custom format strings need to be at least 2 characters long
  229. res.Append(dt.ToString("%" + formatInfo[i].Text, PythonLocale.GetLocaleInfo(context).Time.DateTimeFormat));
  230. break;
  231. }
  232. }
  233. if (postProc) {
  234. res = res.Replace("%f", microseconds != null ? System.String.Format("{0:D6}", microseconds) : "");
  235. res = res.Replace("%j", dt.DayOfYear.ToString("D03")); // day of the year (001 - 366)
  236. // figure out first day of the year...
  237. DateTime first = new DateTime(dt.Year, 1, 1);
  238. int weekOneSunday = (7 - (int)first.DayOfWeek) % 7;
  239. int dayOffset = (8 - (int)first.DayOfWeek) % 7;
  240. // week of year (sunday first day, 0-53), all days before Sunday are 0
  241. res = res.Replace("%U", (((dt.DayOfYear + 6 - weekOneSunday) / 7)).ToString());
  242. // week number of year (monday first day, 0-53), all days before Monday are 0
  243. res = res.Replace("%W", (((dt.DayOfYear + 6 - dayOffset) / 7)).ToString());
  244. res = res.Replace("%w", ((int)dt.DayOfWeek).ToString());
  245. }
  246. return res.ToString();
  247. }
  248. internal static double DateTimeToTimestamp(DateTime dateTime) {
  249. return TicksToTimestamp(RemoveDst(dateTime).Ticks);
  250. }
  251. internal static DateTime TimestampToDateTime(double timeStamp) {
  252. return AddDst(new DateTime(TimestampToTicks(timeStamp)));
  253. }
  254. private static DateTime RemoveDst(DateTime dt) {
  255. return RemoveDst(dt, false);
  256. }
  257. private static DateTime RemoveDst(DateTime dt, bool always) {
  258. #if !SILVERLIGHT
  259. DaylightTime dayTime = TimeZone.CurrentTimeZone.GetDaylightChanges(dt.Year);
  260. if (always || (dt > dayTime.Start && dt < dayTime.End)) {
  261. dt -= dayTime.Delta;
  262. }
  263. #else
  264. if (always || TimeZoneInfo.Local.IsDaylightSavingTime(dt)) {
  265. dt = dt - (TimeZoneInfo.Local.GetUtcOffset(dt) - TimeZoneInfo.Local.BaseUtcOffset);
  266. }
  267. #endif
  268. return dt;
  269. }
  270. private static DateTime AddDst(DateTime dt) {
  271. #if !SILVERLIGHT
  272. DaylightTime dayTime = TimeZone.CurrentTimeZone.GetDaylightChanges(dt.Year);
  273. if (dt > dayTime.Start && dt < dayTime.End) {
  274. dt += dayTime.Delta;
  275. }
  276. #else
  277. if (TimeZoneInfo.Local.IsDaylightSavingTime(dt)) {
  278. dt = dt + (TimeZoneInfo.Local.GetUtcOffset(dt) - TimeZoneInfo.Local.BaseUtcOffset);
  279. }
  280. #endif
  281. return dt;
  282. }
  283. private static double GetTimestampFromObject(object seconds) {
  284. int intSeconds;
  285. if (Converter.TryConvertToInt32(seconds, out intSeconds)) {
  286. return intSeconds;
  287. }
  288. double dblVal;
  289. if (Converter.TryConvertToDouble(seconds, out dblVal)) {
  290. if (dblVal > Int64.MaxValue || dblVal < Int64.MinValue) throw PythonOps.ValueError("unreasonable date/time");
  291. return dblVal;
  292. }
  293. throw PythonOps.TypeError("expected int, got {0}", DynamicHelpers.GetPythonType(seconds));
  294. }
  295. private enum FormatInfoType {
  296. UserText,
  297. SimpleFormat,
  298. CustomFormat,
  299. }
  300. private class FormatInfo {
  301. public FormatInfo(string text) {
  302. Type = FormatInfoType.SimpleFormat;
  303. Text = text;
  304. }
  305. public FormatInfo(FormatInfoType type, string text) {
  306. Type = type;
  307. Text = text;
  308. }
  309. public FormatInfoType Type;
  310. public string Text;
  311. public override string ToString() {
  312. return string.Format("{0}:{1}", Type, Text);
  313. }
  314. }
  315. // temporary solution
  316. private static void AddTime(List<FormatInfo> newFormat) {
  317. newFormat.Add(new FormatInfo("HH"));
  318. newFormat.Add(new FormatInfo(FormatInfoType.UserText, ":"));
  319. newFormat.Add(new FormatInfo("mm"));
  320. newFormat.Add(new FormatInfo(FormatInfoType.UserText, ":"));
  321. newFormat.Add(new FormatInfo("ss"));
  322. }
  323. private static void AddDate(List<FormatInfo> newFormat) {
  324. newFormat.Add(new FormatInfo("MM"));
  325. newFormat.Add(new FormatInfo(FormatInfoType.UserText, "/"));
  326. newFormat.Add(new FormatInfo("dd"));
  327. newFormat.Add(new FormatInfo(FormatInfoType.UserText, "/"));
  328. newFormat.Add(new FormatInfo("yy"));
  329. }
  330. /// <summary>
  331. /// Represents the date components that we found while parsing the date. Used for zeroing out values
  332. /// which have different defaults from CPython. Currently we only know that we need to do this for
  333. /// the year.
  334. /// </summary>
  335. [Flags]
  336. enum FoundDateComponents {
  337. None,
  338. Year = 0x01,
  339. Date = (Year),
  340. }
  341. private static List<FormatInfo> PythonFormatToCLIFormat(string format, bool forParse, out bool postProcess, out FoundDateComponents found) {
  342. postProcess = false;
  343. found = FoundDateComponents.None;
  344. List<FormatInfo> newFormat = new List<FormatInfo>();
  345. for (int i = 0; i < format.Length; i++) {
  346. if (format[i] == '%') {
  347. if (i + 1 == format.Length) throw PythonOps.ValueError("badly formatted string");
  348. switch (format[++i]) {
  349. case 'a': newFormat.Add(new FormatInfo("ddd")); break;
  350. case 'A': newFormat.Add(new FormatInfo("dddd")); break;
  351. case 'b':
  352. newFormat.Add(new FormatInfo("MMM"));
  353. break;
  354. case 'B':
  355. newFormat.Add(new FormatInfo("MMMM"));
  356. break;
  357. case 'c':
  358. found |= FoundDateComponents.Date;
  359. AddDate(newFormat);
  360. newFormat.Add(new FormatInfo(FormatInfoType.UserText, " "));
  361. AddTime(newFormat);
  362. break;
  363. case 'd':
  364. // if we're parsing we want to use the less-strict
  365. // d format and which doesn't require both digits.
  366. if (forParse) newFormat.Add(new FormatInfo(FormatInfoType.CustomFormat, "d"));
  367. else newFormat.Add(new FormatInfo("dd"));
  368. break;
  369. case 'H': newFormat.Add(new FormatInfo("HH")); break;
  370. case 'I': newFormat.Add(new FormatInfo("hh")); break;
  371. case 'm':
  372. newFormat.Add(new FormatInfo(forParse ? "M" : "MM"));
  373. break;
  374. case 'M': newFormat.Add(new FormatInfo(forParse ? "m" : "mm")); break;
  375. case 'p':
  376. newFormat.Add(new FormatInfo(FormatInfoType.CustomFormat, "t"));
  377. newFormat.Add(new FormatInfo(FormatInfoType.UserText, "M"));
  378. break;
  379. case 'S': newFormat.Add(new FormatInfo("ss")); break;
  380. case 'x':
  381. found |= FoundDateComponents.Date;
  382. AddDate(newFormat); break;
  383. case 'X':
  384. AddTime(newFormat);
  385. break;
  386. case 'y':
  387. found |= FoundDateComponents.Year;
  388. newFormat.Add(new FormatInfo("yy"));
  389. break;
  390. case 'Y':
  391. found |= FoundDateComponents.Year;
  392. newFormat.Add(new FormatInfo("yyyy"));
  393. break;
  394. case '%': newFormat.Add(new FormatInfo("\\%")); break;
  395. // format conversions not defined by the CLR. We leave
  396. // them as \\% and then replace them by hand later
  397. case 'j': // day of year
  398. newFormat.Add(new FormatInfo("\\%j"));
  399. postProcess = true;
  400. break;
  401. case 'f':
  402. postProcess = true;
  403. newFormat.Add(new FormatInfo(FormatInfoType.UserText, "%f"));
  404. break;
  405. case 'W': newFormat.Add(new FormatInfo("\\%W")); postProcess = true; break;
  406. case 'U': newFormat.Add(new FormatInfo("\\%U")); postProcess = true; break; // week number
  407. case 'w': newFormat.Add(new FormatInfo("\\%w")); postProcess = true; break; // weekday number
  408. case 'z':
  409. case 'Z':
  410. // !!!TODO:
  411. // 'z' for offset
  412. // 'Z' for time zone name; could be from PythonTimeZoneInformation
  413. newFormat.Add(new FormatInfo(FormatInfoType.UserText, ""));
  414. break;
  415. default:
  416. newFormat.Add(new FormatInfo(FormatInfoType.UserText, "")); break;
  417. }
  418. } else {
  419. if (newFormat.Count == 0 || newFormat[newFormat.Count - 1].Type != FormatInfoType.UserText)
  420. newFormat.Add(new FormatInfo(FormatInfoType.UserText, format[i].ToString()));
  421. else
  422. newFormat[newFormat.Count - 1].Text = newFormat[newFormat.Count - 1].Text + format[i];
  423. }
  424. }
  425. return newFormat;
  426. }
  427. // weekday: Monday is 0, Sunday is 6
  428. internal static int Weekday(DateTime dt) {
  429. if (dt.DayOfWeek == DayOfWeek.Sunday) return 6;
  430. else return (int)dt.DayOfWeek - 1;
  431. }
  432. // isoweekday: Monday is 1, Sunday is 7
  433. internal static int IsoWeekday(DateTime dt) {
  434. if (dt.DayOfWeek == DayOfWeek.Sunday) return 7;
  435. else return (int)dt.DayOfWeek;
  436. }
  437. internal static PythonTuple GetDateTimeTuple(DateTime dt) {
  438. return GetDateTimeTuple(dt, null);
  439. }
  440. internal static PythonTuple GetDateTimeTuple(DateTime dt, PythonDateTime.tzinfo tz) {
  441. int last = -1;
  442. if (tz == null) {
  443. last = -1;
  444. } else {
  445. PythonDateTime.timedelta delta = tz.dst(dt);
  446. PythonDateTime.ThrowIfInvalid(delta, "dst");
  447. if (delta == null) {
  448. last = -1;
  449. } else {
  450. last = delta.__nonzero__() ? 1 : 0;
  451. }
  452. }
  453. return new struct_time(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, Weekday(dt), dt.DayOfYear, last);
  454. }
  455. internal static struct_time GetDateTimeTuple(DateTime dt, bool dstMode) {
  456. return new struct_time(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, Weekday(dt), dt.DayOfYear, dstMode ? 1 : 0);
  457. }
  458. private static DateTime GetDateTimeFromTuple(CodeContext/*!*/ context, PythonTuple t) {
  459. int[] ints;
  460. DateTime res = GetDateTimeFromTupleNoDst(context, t, out ints);
  461. if (ints != null) {
  462. switch (ints[IsDaylightSavingsIndex]) {
  463. // automatic detection
  464. case -1: res = RemoveDst(res); break;
  465. // is daylight savings time, force adjustment
  466. case 1: res = RemoveDst(res, true); break;
  467. }
  468. }
  469. return res;
  470. }
  471. private static DateTime GetDateTimeFromTupleNoDst(CodeContext context, PythonTuple t) {
  472. int[] dummy;
  473. return GetDateTimeFromTupleNoDst(context, t, out dummy);
  474. }
  475. private static DateTime GetDateTimeFromTupleNoDst(CodeContext context, PythonTuple t, out int[] ints) {
  476. if (t == null) {
  477. ints = null;
  478. return DateTime.Now;
  479. }
  480. ints = ValidateDateTimeTuple(context, t);
  481. return new DateTime(ints[YearIndex], ints[MonthIndex], ints[DayIndex], ints[HourIndex], ints[MinuteIndex], ints[SecondIndex]);
  482. }
  483. private static int[] ValidateDateTimeTuple(CodeContext/*!*/ context, PythonTuple t) {
  484. if (t.__len__() != MaxIndex) throw PythonOps.TypeError("expected tuple of length {0}", MaxIndex);
  485. int[] ints = new int[MaxIndex];
  486. for (int i = 0; i < MaxIndex; i++) {
  487. ints[i] = PythonContext.GetContext(context).ConvertToInt32(t[i]);
  488. }
  489. int year = ints[YearIndex];
  490. if (accept2dyear && (year >= 0 && year <= 99)) {
  491. if (year > 68) {
  492. year += 1900;
  493. } else {
  494. year += 2000;
  495. }
  496. }
  497. if (year < DateTime.MinValue.Year || year <= minYear) throw PythonOps.ValueError("year is too low");
  498. if (year > DateTime.MaxValue.Year) throw PythonOps.ValueError("year is too high");
  499. if (ints[WeekdayIndex] < 0 || ints[WeekdayIndex] >= 7) throw PythonOps.ValueError("day of week is outside of 0-6 range");
  500. return ints;
  501. }
  502. private static int FindFormat(List<FormatInfo> formatInfo, string format) {
  503. for (int i = 0; i < formatInfo.Count; i++) {
  504. if (formatInfo[i].Text == format) return i;
  505. }
  506. return -1;
  507. }
  508. #if !SILVERLIGHT // Stopwatch
  509. private static void InitStopWatch() {
  510. if (sw == null) {
  511. sw = new Stopwatch();
  512. sw.Start();
  513. }
  514. }
  515. #endif
  516. [PythonType]
  517. public class struct_time : PythonTuple {
  518. private static PythonType _StructTimeType = DynamicHelpers.GetPythonTypeFromType(typeof(struct_time));
  519. public object tm_year {
  520. get { return _data[0]; }
  521. }
  522. public object tm_mon {
  523. get { return _data[1]; }
  524. }
  525. public object tm_mday {
  526. get { return _data[2]; }
  527. }
  528. public object tm_hour {
  529. get { return _data[3]; }
  530. }
  531. public object tm_min {
  532. get { return _data[4]; }
  533. }
  534. public object tm_sec {
  535. get { return _data[5]; }
  536. }
  537. public object tm_wday {
  538. get { return _data[6]; }
  539. }
  540. public object tm_yday {
  541. get { return _data[7]; }
  542. }
  543. public object tm_isdst {
  544. get { return _data[8]; }
  545. }
  546. internal struct_time(int year, int month, int day, int hour, int minute, int second, int dayOfWeek, int dayOfYear, int isDst)
  547. : base(new object[] { year, month, day, hour, minute, second, dayOfWeek, dayOfYear, isDst }) {
  548. }
  549. internal struct_time(PythonTuple sequence)
  550. : base(sequence) {
  551. }
  552. public static struct_time __new__(CodeContext context, PythonType cls, int year, int month, int day, int hour, int minute, int second, int dayOfWeek, int dayOfYear, int isDst) {
  553. if (cls == _StructTimeType) {
  554. return new struct_time(year, month, day, hour, minute, second, dayOfWeek, dayOfYear, isDst);
  555. } else {
  556. struct_time st = cls.CreateInstance(context, year, month, day, hour, minute, second, dayOfWeek, dayOfYear, isDst) as struct_time;
  557. if (st == null)
  558. throw PythonOps.TypeError("{0} is not a subclass of time.struct_time", cls);
  559. return st;
  560. }
  561. }
  562. public static struct_time __new__(CodeContext context, PythonType cls, [NotNull]PythonTuple sequence) {
  563. if (sequence.__len__() != 9) {
  564. throw PythonOps.TypeError("time.struct_time() takes a 9-sequence ({0}-sequence given)", sequence.__len__());
  565. }
  566. if (cls == _StructTimeType) {
  567. return new struct_time(sequence);
  568. } else {
  569. struct_time st = cls.CreateInstance(context, sequence) as struct_time;
  570. if (st == null) {
  571. throw PythonOps.TypeError("{0} is not a subclass of time.struct_time", cls);
  572. }
  573. return st;
  574. }
  575. }
  576. public static struct_time __new__(CodeContext context, PythonType cls, [NotNull]IEnumerable sequence) {
  577. return __new__(context, cls, PythonTuple.Make(sequence));
  578. }
  579. public PythonTuple __reduce__() {
  580. return PythonTuple.MakeTuple(_StructTimeType, PythonTuple.MakeTuple(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst));
  581. }
  582. public static object __getnewargs__(CodeContext context, int year, int month, int day, int hour, int minute, int second, int dayOfWeek, int dayOfYear, int isDst) {
  583. return PythonTuple.MakeTuple(struct_time.__new__(context, _StructTimeType, year, month, day, hour, minute, second, dayOfWeek, dayOfYear, isDst));
  584. }
  585. }
  586. }
  587. }