public void TestDateTime() { TimeZoneInfo tziNewYork; try { tziNewYork = TimeZoneConverter.TZConvert.GetTimeZoneInfo("Eastern Standard Time"); } catch { // Ignore issues with locally installed timezones. return; } var tz = new HaystackTimeZone("New_York"); HaystackDateTime ts; ts = new HaystackDateTime(new DateTime(634429600180690000L), tz); VerifyZinc(ts, "2011-06-06T12:26:58.069-05:00 New_York"); Assert.AreEqual(ts.TimeZone.Name, "New_York"); Assert.AreEqual(ts.TimeZone.TimeZoneInfo, tziNewYork); // convert back to millis ts = ZincReader.ReadValue <HaystackDateTime>("2011-06-06T12:26:58.069-04:00 New_York"); Assert.AreEqual(ts.Value.Ticks, 634429600180690000L); // different timezones ts = new HaystackDateTime(new DateTime(630850574400000000L), new HaystackTimeZone("New_York")); VerifyZinc(ts, "2000-02-02T03:04:00-05:00 New_York"); ts = new HaystackDateTime(new DateTime(630850754400000000L), new HaystackTimeZone("UTC")); VerifyZinc(ts, "2000-02-02T08:04:00Z UTC"); ts = new HaystackDateTime(new DateTime(630851042400000000L), new HaystackTimeZone("Taipei")); VerifyZinc(ts, "2000-02-02T16:04:00+08:00 Taipei"); }
private void VerifyTz(string name, params string[] dntzIds) { var tz = new HaystackTimeZone(name); // Ignore issues with locally installed timezones. if (tz == null) { return; } var dntz = tz.TimeZoneInfo; Assert.AreEqual(tz.Name, name); Assert.IsTrue(dntzIds.Contains(dntz.Id), $"{dntz.Id} not in [{string.Join(", ", dntzIds)}]"); }
public void TestDateTime() { var dt = HaystackToken.dateTime; var ny = new HaystackTimeZone("New_York"); var utc = HaystackTimeZone.UTC; var london = new HaystackTimeZone("London"); // Ignore issues with locally installed timezones. if (ny != null) { VerifyToks("2016-01-13T09:51:33-05:00 New_York", new object[] { dt, new HaystackDateTime(new DateTime(2016, 1, 13, 9, 51, 33), ny /*, tzOffset(-5, 0)*/) }); VerifyToks("2016-01-13T09:51:33.353-05:00 New_York", new object[] { dt, new HaystackDateTime(new HaystackDate(2016, 1, 13), new HaystackTime(new TimeSpan(0, 9, 51, 33, 353)), ny /*, tzOffset(-5, 0)*/) }); } VerifyToks("2010-12-18T14:11:30.924Z", new object[] { dt, new HaystackDateTime(new HaystackDate(2010, 12, 18), new HaystackTime(new TimeSpan(0, 14, 11, 30, 924)), utc) }); VerifyToks("2010-12-18T14:11:30.924Z UTC", new object[] { dt, new HaystackDateTime(new HaystackDate(2010, 12, 18), new HaystackTime(new TimeSpan(0, 14, 11, 30, 924)), utc) }); // Ignore issues with locally installed timezones. if (london != null) { VerifyToks("2010-12-18T14:11:30.924Z London", new object[] { dt, new HaystackDateTime(new HaystackDate(2010, 12, 18), new HaystackTime(new TimeSpan(0, 14, 11, 30, 924)), london) }); } // Apparently PST8PDT is not valid in java? - Not Tested for windows either // verifyToks("2015-01-02T06:13:38.701-08:00 PST8PDT", new Object[] {dt, new HaystackDateTime(new HaystackDate(2015,1,2), new HaystackTime(6,13,38,701), new HaystackTimeZone("PST8PDT"), tzOffset(-8,0))}); var tz = new HaystackTimeZone("GMT+5"); // Ignore issues with locally installed timezones. if (tz != null) { VerifyToks("2010-03-01T23:55:00.013-05:00 GMT+5", new object[] { dt, new HaystackDateTime(new HaystackDate(2010, 3, 1), new HaystackTime(new TimeSpan(0, 23, 55, 0, 13)), tz /*, tzOffset(-5, 0)*/) }); } tz = new HaystackTimeZone("GMT-10"); // Ignore issues with locally installed timezones. if (tz != null) { VerifyToks("2010-03-01T23:55:00.013+10:00 GMT-10 ", new object[] { dt, new HaystackDateTime(new HaystackDate(2010, 3, 1), new HaystackTime(new TimeSpan(0, 23, 55, 0, 13)), tz /*, tzOffset(10, 0)*/) }); } }
private HaystackToken dateTime(StringBuilder s) { bool bFlag1 = true; // xxx timezone if ((_currentChar < 0 || _peekChar < 0) || ((char)_currentChar != ' ' || !char.IsUpper((char)_peekChar))) { if (s[s.Length - 1] == 'Z') { s.Append(" UTC"); } else { err("Expecting timezone"); } bFlag1 = false; } if (bFlag1) { consume(); s.Append(' '); while (isIdPart(_currentChar)) { s.Append((char)_currentChar); consume(); } // handle GMT+xx or GMT-xx if ((_currentChar == '+' || _currentChar == '-') && s.ToString().EndsWith("GMT")) { s.Append((char)_currentChar); consume(); while (isDigit(_currentChar)) { s.Append((char)_currentChar); consume(); } } } // Tested 17.06.2018 with 2018-06-17T13:00:00.123+10:00 Melbourne string sCurrent = s.ToString(); bool bUTC = false; bool bNoZoneOffset = false; string strDateTimeOnly = ""; string strDateTimeOffsetFormatSpecifier = ""; string strHTimeZone = ""; int iPosOfLastSecondChar, iPosOfSpaceBeforeTZID = 0; DateTimeOffset dto; TimeSpan tsOffset = new TimeSpan(); if (sCurrent.Contains('W')) { throw new FormatException("Invalid DateTime format for string " + s + " ISO8601 W specifier not supported by this toolkit"); } if (sCurrent.Trim().Contains("Z UTC")) { bUTC = true; int iPos = sCurrent.IndexOf('Z'); iPosOfLastSecondChar = iPos - 1; strDateTimeOnly = sCurrent.Substring(0, iPos); } else if (sCurrent.Trim().Contains("Z")) { bUTC = true; int iPos = sCurrent.IndexOf('Z'); iPosOfLastSecondChar = iPos - 1; strDateTimeOnly = sCurrent.Substring(0, iPos); } if (!sCurrent.Contains('T')) { // Only possible in ISO 8601 with just a date - this is not an allowed case for Haystack DateTime throw new FormatException("Invalid DateTime format for string " + s + " missing ISO8601 T specifier"); } // if it is offset with name then it must have a + or - sign for the offset after the T int iPosOfT = sCurrent.IndexOf('T'); if (iPosOfT + 1 >= sCurrent.Length) { // Nothing after 'T' this is not legal throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier"); } // Stip of the timezone by finding the space iPosOfSpaceBeforeTZID = sCurrent.IndexOf(' ', iPosOfT); int iEndLen = iPosOfSpaceBeforeTZID - (iPosOfT + 1); string sEnd = sCurrent.Substring(iPosOfT + 1, iEndLen); if (!bUTC) { if ((sEnd.Trim().Contains('+')) || (sEnd.Trim().Contains('-'))) { bool bPositive = false; int iPosSign = 0; // In ISO 8601 this is either a +/-hh:mm or +/-hhmm or +/-hh // See how many characters there is till space - that is the offset specifier if (sEnd.Trim().Contains('+')) { bPositive = true; iPosSign = sCurrent.IndexOf('+', iPosOfT); } else { iPosSign = sCurrent.IndexOf('-', iPosOfT); } iPosOfLastSecondChar = iPosSign - 1; strDateTimeOnly = sCurrent.Substring(0, iPosSign); // Find the next space - requires it contains a Haystack Zone specifier if not UTC int iPosSpace = sCurrent.Trim().IndexOf(' ', iPosSign); if ((iPosSpace < iPosSign) || (iPosSpace < 0)) { throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier"); } // What is the number of characters between the sign and the space - 5 4 or 2 iPosOfSpaceBeforeTZID = iPosSpace; int iNumOffsetChars = iPosSpace - iPosSign - 1; string strOffset = sCurrent.Substring(iPosSign + 1, iNumOffsetChars); if (iNumOffsetChars == 5) { // Assume +/-hh:mm string[] strHM = strOffset.Split(':'); if (strHM.Length != 2) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } int iHour; if (!int.TryParse(strHM[0], out iHour)) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } if (iHour < 0) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } int iMinute; if (!int.TryParse(strHM[1], out iMinute)) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } if ((iMinute < 0) || (iMinute > 60)) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } if (!bPositive) { // Problem: if minute is non-zero we will get undesired result e.g. -10:10 will return -9:50 therefore both must be negative iMinute = iMinute * -1; iHour = iHour * -1; } tsOffset = new TimeSpan(iHour, iMinute, 0); } else if (iNumOffsetChars == 4) { int iHour; // Assume hhmm if (!int.TryParse(strOffset.Substring(0, 2), out iHour)) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } if (iHour < 0) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } int iMinute; if (!int.TryParse(strOffset.Substring(2, 2), out iMinute)) { throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } if ((iMinute < 0) || (iMinute > 60)) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } if (!bPositive) { // Problem: if minute is non-zero we will get undesired result e.g. -10:10 will return -9:50 therefore both must be negative iMinute = iMinute * -1; iHour = iHour * -1; } tsOffset = new TimeSpan(iHour, iMinute, 0); } else if (iNumOffsetChars == 2) { // Assume hh int iHour; // Assume hhmm if (!int.TryParse(strOffset, out iHour)) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } if (iHour < 0) { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } if (!bPositive) { iHour = iHour * -1; } tsOffset = new TimeSpan(iHour, 0, 0); } else { // Invalid offset throw new FormatException("Invalid DateTime format for string " + s + " missing suitable length string after ISO8601 T specifier for offset"); } } else { // Must not contain a Zone offset string bNoZoneOffset = true; iPosOfSpaceBeforeTZID = sCurrent.IndexOf(' ', iPosOfT); strDateTimeOnly = sCurrent.Substring(0, iPosOfSpaceBeforeTZID); } } // Get the Haystack time zone identifier and create the HTimeZone object. if ((iPosOfSpaceBeforeTZID < sCurrent.Length) && (sCurrent.Length - iPosOfSpaceBeforeTZID > 2) && (!bUTC)) { strHTimeZone = sCurrent.Substring(iPosOfSpaceBeforeTZID + 1); } // Check for the 'T' for the Formats that include that // Check for milliseconds if (strDateTimeOnly.Trim().Contains(".")) { // All fields with 'T' strDateTimeOffsetFormatSpecifier = "yyyy-MM-dd'T'HH:mm:ss.FFF"; } else { // no milliseconds // DateTimeOffset will adopt 0 milliseconds strDateTimeOffsetFormatSpecifier = "yyyy-MM-dd'T'HH:mm:ss"; } try { DateTime dt = DateTime.ParseExact(strDateTimeOnly, strDateTimeOffsetFormatSpecifier, CultureInfo.InvariantCulture); if (!bNoZoneOffset) { dto = new DateTimeOffset(dt, tsOffset); } else if (bUTC) { DateTime dtutc = System.DateTime.SpecifyKind(dt, DateTimeKind.Utc); dto = new DateTimeOffset(dtutc); } else { dto = new DateTimeOffset(dt); } } catch (Exception) { throw new FormatException("Invalid DateTime format for string " + s); } HaystackTimeZone htz; if (bUTC) { htz = HaystackTimeZone.UTC; } else { try { htz = new HaystackTimeZone(strHTimeZone); } catch (Exception genexcep) { throw new FormatException("Invalid DateTime format for string " + s + " for Timezone [" + genexcep.Message + "]"); } } _currentValue = new HaystackDateTime(dto, htz); return(HaystackToken.dateTime); }
public void Make_sidney() { var tz = new HaystackTimeZone("Sydney"); Assert.IsTrue(new[] { "AUS Eastern Standard Time", "Australia/Sydney" }.Contains(tz.TimeZoneInfo.Id)); }
public void Make_utc() { var tz = new HaystackTimeZone("UTC"); Assert.IsTrue(new[] { "UTC", "Etc/UTC" }.Contains(tz.TimeZoneInfo.Id)); }