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)*/) });
            }
        }
Ejemplo n.º 4
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));
        }