From f50e275f301c3c4ddd461acad13f6e32cbeda9cf Mon Sep 17 00:00:00 2001 From: j-troc Date: Fri, 21 Dec 2018 17:30:48 +0100 Subject: [PATCH 1/6] Add Calendar class --- source/icu.net.tests/CalendarTests.cs | 388 +++++++++ source/icu.net/Calendar/Calendar.cs | 817 ++++++++++++++++++ source/icu.net/Calendar/GregorianCalendar.cs | 48 + .../NativeMethods/NativeMethods_Calendar.cs | 404 +++++++++ 4 files changed, 1657 insertions(+) create mode 100644 source/icu.net.tests/CalendarTests.cs create mode 100644 source/icu.net/Calendar/Calendar.cs create mode 100644 source/icu.net/Calendar/GregorianCalendar.cs create mode 100644 source/icu.net/NativeMethods/NativeMethods_Calendar.cs diff --git a/source/icu.net.tests/CalendarTests.cs b/source/icu.net.tests/CalendarTests.cs new file mode 100644 index 00000000..4f2e0579 --- /dev/null +++ b/source/icu.net.tests/CalendarTests.cs @@ -0,0 +1,388 @@ +using System; +using NUnit.Framework; +using Icu; +using System.Globalization; +using System.Linq; + + +namespace Icu.Tests +{ + [TestFixture] + class CalendarTests + { + + [Test] + public void GetTimeZoneDisplayNameTest() + { + var timezone = new TimeZone("AST"); + var cal = new GregorianCalendar(timezone); + + var displayName = cal.GetTimeZoneDisplayName(Calendar.UCalendarDisplayNameType.Standard); + + Assert.AreEqual("Alaska Standard Time", displayName); + } + + [Test] + public void ClearTest() + { + var cal = new GregorianCalendar(); + cal.Month = Calendar.UCalendarMonths.September; + cal.DayOfMonth = 4; + + cal.Clear(); + + Assert.AreEqual(Calendar.UCalendarMonths.January, cal.Month); + Assert.AreEqual(1, cal.DayOfMonth); + } + + [Test] + public void ClearFieldTest() + { + var cal = new GregorianCalendar(); + cal.Month = Calendar.UCalendarMonths.September; + + cal.Clear(Calendar.UCalendarDateFields.Month); + + Assert.AreEqual(Calendar.UCalendarMonths.January, cal.Month); + } + + [Test] + public void CloneTest() + { + var cal1 = new GregorianCalendar(); + + cal1.DayOfMonth = 5; + var cal2 = cal1.Clone(); + cal2.DayOfMonth = 10; + + Assert.AreEqual(5, cal1.DayOfMonth); + } + + [Test] + public void RollTest() + { + var cal = new GregorianCalendar(); + var startMonth = cal.Month; + + cal.Roll(Calendar.UCalendarDateFields.DayOfMonth, 100); + + Assert.AreEqual(startMonth, cal.Month); + } + + [Test] + public void SetTest() + { + var cal = new GregorianCalendar(new TimeZone("UTC")); + cal.Clear(); + + cal.Set(Calendar.UCalendarDateFields.DayOfYear, 2); + + Assert.AreEqual(24 * 60 * 60 * 1000, cal.GetTime()); + } + + [Test] + public void GetTest() + { + var cal = new GregorianCalendar(new TimeZone("UTC")); + var expected = 15; + cal.Set(Calendar.UCalendarDateFields.DayOfYear, expected); + + var result = cal.Get(Calendar.UCalendarDateFields.DayOfYear); + + Assert.AreEqual(expected, result); + } + + [Test] + public void FieldDifferenceTest() + { + var cal = new GregorianCalendar(); + var time = cal.GetTime(); + + cal.Add(Calendar.UCalendarDateFields.Hour, 2); + cal.Add(Calendar.UCalendarDateFields.Minute, 2); + + var difference = cal.FieldDifference(time, Calendar.UCalendarDateFields.Minute); + + Assert.AreEqual(time, cal.GetTime()); + Assert.AreEqual(-122, difference); + } + + [Test] + public void IsSetTest() + { + var cal = new GregorianCalendar(); + cal.Month = Calendar.UCalendarMonths.September; + cal.DayOfMonth = 4; + + var setBefore = cal.IsSet(Calendar.UCalendarDateFields.Month); + cal.Clear(); + var setAfter = cal.IsSet(Calendar.UCalendarDateFields.Month); + + Assert.AreEqual(true, setBefore); + Assert.AreEqual(false, setAfter); + } + + [Test] + public void InDaylightTime() + { + var cal = new GregorianCalendar(new TimeZone("Europe/Warsaw")); + + cal.Month = Calendar.UCalendarMonths.September; + cal.DayOfMonth = 1; + + Assert.AreEqual(true, cal.InDaylightTime()); + } + + [Test] + public void SetTimeTest() + { + var cal = new GregorianCalendar(new TimeZone("UTC")); + cal.SetTime(0); + + Assert.AreEqual(1970, cal.Year); + Assert.AreEqual(0, cal.Hour); + Assert.AreEqual(0, cal.Minute); + Assert.AreEqual(0, cal.Millisecond); + } + + [Test] + public void ToDateTimeTest() + { + var cal = new GregorianCalendar(); + var datetime = cal.ToDateTime(); + + Assert.AreEqual(cal.Year, datetime.Year); + Assert.AreEqual((int)cal.Month + 1, datetime.Month); + Assert.AreEqual(cal.DayOfMonth, datetime.Day); + Assert.AreEqual(cal.HourOfDay, datetime.Hour); + Assert.AreEqual(cal.Minute, datetime.Minute); + Assert.AreEqual(cal.Second, datetime.Second); + Assert.AreEqual(cal.Millisecond, datetime.Millisecond); + } + + [Test] + public void SetTimeZoneTest() + { + var expected = new TimeZone("AST"); + var cal = new GregorianCalendar(new TimeZone("UTC")); + + cal.SetTimeZone(expected); + var result = cal.GetTimeZone(); + + Assert.AreEqual(expected.Id, result.Id); + } + + [Test] + public void FirstDayOfWeekTest() + { + var cal = new GregorianCalendar(new TimeZone("UTC")); + var newDay = Calendar.UCalendarDaysOfWeek.Thursday; + + var val0 = cal.FirstDayOfWeek; + cal.FirstDayOfWeek = newDay; + var val1 = cal.FirstDayOfWeek; + + Assert.AreEqual(Calendar.UCalendarDaysOfWeek.Sunday, val0); + Assert.AreEqual(newDay, val1); + } + + [Test] + public void WeekOfYearTest() + { + var cal = new GregorianCalendar(new TimeZone("UTC")); + cal.Clear(); + cal.DayOfMonth = 4; + var newDay = Calendar.UCalendarDaysOfWeek.Thursday; + + var val0 = cal.WeekOfYear; + cal.FirstDayOfWeek = newDay; + var val1 = cal.WeekOfYear; + + + Assert.AreEqual(2, val0); + Assert.AreEqual(1, val1); + } + + [Test] + public void MinimalDaysInFirstWeekTest() + { + var cal = new GregorianCalendar(new TimeZone("UTC")); + cal.Clear(); + cal.DayOfMonth = 4; + var newMinimum = 5; + + var val0 = cal.WeekOfYear; + cal.MinimalDaysInFirstWeek = newMinimum; + var val1 = cal.WeekOfYear; + + Assert.AreEqual(2, val0); + Assert.AreEqual(1, val1); + } + + [Test] + public void SkippedWallTimeTest() + { + var cal = new GregorianCalendar(new TimeZone("America/New_York")); + cal.Year = 2011; + cal.HourOfDay = 0; + cal.Minute = 0; + cal.Month = Calendar.UCalendarMonths.March; + cal.DayOfMonth = 13; + + cal.SkippedWallTimeOption = Calendar.UCalendarWallTimeOption.WalltimeFirst; + cal.Minute = 30; + cal.HourOfDay = 2; + var hour = cal.HourOfDay; + var minute = cal.Minute; + + Assert.AreEqual(1, hour); + Assert.AreEqual(30, minute); + } + + [Test] + public void RepeatedWallTimeTest() + { + var cal = new GregorianCalendar(new TimeZone("America/New_York")); + cal.Year = 2011; + cal.HourOfDay = 0; + cal.Minute = 0; + cal.Month = Calendar.UCalendarMonths.November; + cal.DayOfMonth = 6; + + cal.RepeatedWallTimeOption = Calendar.UCalendarWallTimeOption.WalltimeFirst; + cal.Minute = 30; + cal.HourOfDay = 1; + cal.Add(Calendar.UCalendarDateFields.Minute, 60); + var hour = cal.HourOfDay; + var minute = cal.Minute; + + Assert.AreEqual(1, hour); + Assert.AreEqual(30, minute); + } + + [Test] + public void LenientTest_ThrowsArgumentException() + { + + var cal = new GregorianCalendar(new TimeZone("America/New_York")); + cal.Year = 2011; + cal.HourOfDay = 0; + cal.Minute = 0; + cal.Month = Calendar.UCalendarMonths.March; + cal.DayOfMonth = 13; + + cal.Lenient = false; + cal.SkippedWallTimeOption = Calendar.UCalendarWallTimeOption.WalltimeFirst; + cal.Minute = 30; + cal.HourOfDay = 2; + + Assert.Throws(() => cal.GetTime()); + } + + [Test] + public void WeekOfMonthTest() + { + var cal = new GregorianCalendar(new TimeZone("UTC")); + cal.Clear(); + cal.DayOfMonth = 4; + var newMinimum = 5; + + var val0 = cal.WeekOfMonth; + cal.MinimalDaysInFirstWeek = newMinimum; + var val1 = cal.WeekOfMonth; + + Assert.AreEqual(2, val0); + Assert.AreEqual(1, val1); + } + + [Test] + public void EraTest() + { + var cal = new GregorianCalendar(new TimeZone("UTC")); + + var era1 = cal.Era; + cal.Year = -1; + var era0 = cal.Era; + + Assert.AreEqual(1, era1); + Assert.AreEqual(0, era0); + } + + [Test] + public void ZoneOffsetTest() + { + var expected = 60 * 60 * 1000; + var zone = new TimeZone("Europe/Paris"); + var cal = new GregorianCalendar(zone); + + var offset = cal.ZoneOffset; + + Assert.AreEqual(expected, offset); + } + + [Test] + public void DstOffsetTest() + { + var expected0 = 60 * 60 * 1000; + var expected1 = 0; + + var zone = new TimeZone("Europe/Paris"); + var cal = new GregorianCalendar(zone); + cal.Month = Calendar.UCalendarMonths.July; + cal.DayOfMonth = 20; + + var offset0 = cal.DstOffset; + cal.Month = Calendar.UCalendarMonths.January; + var offset1 = cal.DstOffset; + + Assert.AreEqual(expected0, offset0); + Assert.AreEqual(expected1, offset1); + + } + + [Test] + public void AmPmTest() + { + var cal = new GregorianCalendar(new TimeZone("UTC")); + + cal.HourOfDay = 3; + var val0 = cal.AmPm; + cal.HourOfDay = 14; + var val1 = cal.AmPm; + + Assert.AreEqual(0, val0); + Assert.AreEqual(1, val1); + } + + [Test] + + public void SetTimeZone2Test() + { + var winId = "Romance Standard Time"; + var expected = "Europe/Paris"; + var timezone = TimeZoneInfo.FindSystemTimeZoneById(winId); + var cal = new GregorianCalendar(new TimeZone("UTC")); + + cal.SetTimeZone(timezone); + + var tz = cal.GetTimeZone(); + + Assert.AreEqual(expected, tz.Id); + } + + [Test] + public void GetTimeZoneTest() + { + var timezone = new TimeZone("Europe/Zagreb"); + var expected = "Central European Standard Time"; + + var cal = new GregorianCalendar(timezone); + + var tz = cal.GetTimeZoneInfo(); + + Assert.AreEqual(expected, tz.Id); + } + + + } +} diff --git a/source/icu.net/Calendar/Calendar.cs b/source/icu.net/Calendar/Calendar.cs new file mode 100644 index 00000000..c655ea88 --- /dev/null +++ b/source/icu.net/Calendar/Calendar.cs @@ -0,0 +1,817 @@ +using System; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Linq; + +#if NETSTANDARD1_6 +using Icu; +#else +using System.Globalization; +using System.Runtime.ConstrainedExecution; +#endif + +namespace Icu +{ + public abstract class Calendar : IDisposable + { + public enum UCalendarDateFields + { + Era, + Year, + Month, + WeekOfYear, + WeekOfMonth, + Date, + DayOfYear, + DayOfWeek, + DayOfWeekInMonth, + AmPm, + Hour, + HourOfDay, + Minute, + Second, + Millisecond, + ZoneOffset, + DstOffset, + YearWoy, + DowLocal, + ExtendedYear, + JulianYear, + MillisecondsInDay, + IsLeapMonth, + FieldCount, + DayOfMonth = Date + }; + + public enum UCalendarType + { + Traditional, + Default = Traditional, + Gregorian + } + + public enum UCalendarDisplayNameType + { + Standard, + ShortStandard, + Dst, + ShortDst + }; + + public enum UCalendarAttribute + { + Lenient, + FirstDayOfWeek, + MinimalDaysInFirstWeek, + RepeatedWallTime, + SkippedWallTime + }; + + public enum UCalendarWallTimeOption + { + WalltimeLast, + WalltimeFirst, + WalltimeNextValid + }; + + public enum UCalendarDaysOfWeek + { + Sunday = 1, + Monday, + Tuesday, + Wednesday, + Thursday, + Friday, + Saturday + }; + + public enum UCalendarMonths + { + January, + February, + March, + April, + May, + June, + July, + August, + September, + October, + November, + December, + Undecimber + }; + + public enum UCalendarAMPMs + { + Am, + Pm + }; + + internal protected sealed class SafeCalendarHandle : SafeHandle + { + public SafeCalendarHandle() : + base(IntPtr.Zero, true) + { } + + /// + /// When overridden in a derived class, executes the code required to free the handle. + /// + /// + /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. + /// In this case, it generates a ReleaseHandleFailed Managed Debugging Assistant. + /// +#if !NETSTANDARD1_6 + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] +#endif + protected override bool ReleaseHandle() + { + if (handle != IntPtr.Zero) + NativeMethods.ucal_close(handle); + handle = IntPtr.Zero; + return true; + } + + /// + ///When overridden in a derived class, gets a value indicating whether the handle value is invalid. + /// + /// + ///true if the handle is valid; otherwise, false. + /// + public override bool IsInvalid + { + get { return handle == IntPtr.Zero; } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + ReleaseHandle(); + } + } + + private bool _disposingValue; // To detect redundant calls + protected SafeCalendarHandle _calendarHandle = default(SafeCalendarHandle); + protected Locale _locale; + + + /// + /// Gets this Calendar's time as milliseconds. + /// + /// The current time in UTC (GMT) time, or zero if the operation failed. + public double GetTime() + { + var millis = NativeMethods.ucal_getMillis(_calendarHandle, out ErrorCode ec); + ExceptionFromErrorCode.ThrowIfError(ec); + + return millis; + } + + /// + /// Create and return a polymorphic copy of this calendar. + /// + /// A polymorphic copy of this calendar. + public abstract Calendar Clone(); + + /// + /// Sets this Calendar's current time with the given date. + ///The time specified should be in non-local UTC(GMT) time. + /// + /// The given date in UTC (GMT) time. + public void SetTime(double date) + { + NativeMethods.ucal_setMillis(_calendarHandle, date, out ErrorCode ec); + ExceptionFromErrorCode.ThrowIfError(ec); + } + + /// + /// Sets this Calendar's current time with the given date. + ///The time specified should be in non-local UTC(GMT) time. + /// + /// The given date in UTC (GMT) time. + public void SetTime(DateTime dateTime) + { + Year = dateTime.Year; + Month = (Calendar.UCalendarMonths)(dateTime.Month - 1); + DayOfMonth = dateTime.Day; + HourOfDay = dateTime.Hour; + Minute = dateTime.Minute; + Second = dateTime.Second; + Millisecond = dateTime.Millisecond; + + //correct for utc + Add(UCalendarDateFields.Millisecond, ZoneOffset); + } + + /// + /// Adds the specified(signed) amount of time to the given time field, based on the calendar's rules. + /// + /// For example, to subtract 5 days from the current time of the calendar, call add(Calendar::DATE, -5). + /// When adding on the month or Calendar::MONTH field, other fields like date might conflict and need to be changed. + /// For instance, adding 1 month on the date 01/31/96 will result in 02/29/96. Adding a positive value always means + /// moving forward in time, so for the Gregorian calendar, starting with 100 BC and adding +1 to year results in 99 BC + /// (even though this actually reduces the numeric value of the field itself). + /// + /// Specifies which date field to modify. + /// The amount of time to be added to the field, in the natural unit for that field (e.g., days for the day fields, hours for the hour field.) + public void Add(UCalendarDateFields field, int amount) + { + NativeMethods.ucal_add(_calendarHandle, field, amount, out ErrorCode ec); + ExceptionFromErrorCode.ThrowIfError(ec); + } + + /// + /// Time Field Rolling function. + /// + /// The only difference between roll() and add() is that roll() does not change the value of more significant fields + /// when it reaches the minimum or maximum of its range, whereas add() does. + /// + /// The time field. + /// Indicates amount to roll. + public void Roll(UCalendarDateFields field, int amount) + { + NativeMethods.ucal_roll(_calendarHandle, field, amount, out ErrorCode ec); + ExceptionFromErrorCode.ThrowIfError(ec); + } + + /// + /// Return the difference between the given time and the time this calendar object is set to. + /// + /// If this calendar is set before the given time, the returned value will be positive. + /// If this calendar is set after the given time, the returned value will be negative. + /// The field parameter specifies the units of the return value. + /// + /// As a side effect of this call, this calendar is advanced toward when by the given amount. + /// That is, calling this method has the side effect of calling add(field, n), where n is the return value. + /// + /// Usage: To use this method, call it first with the largest field of interest, then with progressively smaller fields. + /// + /// the date to compare this calendar's time to + /// the field in which to compute the result + /// + public int FieldDifference(double when, UCalendarDateFields field) + { + var result = NativeMethods.ucal_getFieldDifference(_calendarHandle, when, field, out ErrorCode ec); + ExceptionFromErrorCode.ThrowIfError(ec); + + return result; + } + + /// + /// Gets the value for a given time field. + /// + /// The given time field. + /// The value for the given time field, or zero if the field is unset, and set() has been called for any other field. + public int Get(UCalendarDateFields field) + { + int val = NativeMethods.ucal_get(_calendarHandle, field, out ErrorCode ec); + ExceptionFromErrorCode.ThrowIfError(ec); + return val; + } + + /// + /// Sets the given time field with the given value. + /// + /// The given time field. + /// The value to be set for the given time field. + public void Set(UCalendarDateFields field, int value) + { + NativeMethods.ucal_set(_calendarHandle, field, value); + } + + /// + /// Determines if the given time field has a value set. + /// + /// The given time field. + /// True if the given time field has a value set; false otherwise. + public bool IsSet(UCalendarDateFields field) + { + return NativeMethods.ucal_isSet(_calendarHandle, field); + } + + /// + /// Clears the values of all the time fields, making them both unset and assigning them a value of zero. + /// + public void Clear() + { + NativeMethods.ucal_clear(_calendarHandle); + } + + /// + /// Clears the value in the given time field, both making it unset and assigning it a value of zero. + /// + /// The time field to be cleared. + public void Clear(UCalendarDateFields field) + { + NativeMethods.ucal_clearField(_calendarHandle, field); + } + + /// + /// Sets the calendar's time zone to be the same as the one passed in. + /// + /// The given time zone. + public void SetTimeZone(TimeZone timezone) + { + SetTimeZone(timezone.Id); + } + + /// + /// Sets the calendar's time zone to be equivalent to the one passed in. + /// + /// The given time zone info. + public void SetTimeZone(TimeZoneInfo timeZoneInfo) + { + var id = timeZoneInfo.Id; + + var converted = TimeZone.GetIdForWindowsId(id, _locale?.Country); + + if (!string.IsNullOrWhiteSpace(converted)) + { + id = converted; + } + + SetTimeZone(id); + } + + /// + /// Returns time zone set for this calendar. + /// + /// Time zone set for this calendar. + public TimeZone GetTimeZone() + { + int length = NativeMethods.ucal_getTimeZoneId(_calendarHandle, out string result, 32, out ErrorCode ec); + if (length >= 32) + { + ec = ErrorCode.NoErrors; + NativeMethods.ucal_getTimeZoneId(_calendarHandle, out result, length+1, out ec); + } + ExceptionFromErrorCode.ThrowIfError(ec); + return new TimeZone(result); + } + + /// + /// Returns time zone info for time zone set for this calendar. + /// + /// Time zone info for this calendar. + public TimeZoneInfo GetTimeZoneInfo() + { + var id = GetTimeZone().Id; + + var timeZoneInfo = TimeZoneInfo.GetSystemTimeZones().FirstOrDefault(zone => zone.Id == id); + + if(timeZoneInfo != null) + { + return timeZoneInfo; + } + + string winid = TimeZone.GetWindowsId(id); + + if (!string.IsNullOrWhiteSpace(winid)) + { + id = winid; + } + + return TimeZoneInfo.FindSystemTimeZoneById(id); + } + + public abstract bool InDaylightTime(); + + /// + /// Returns the current UTC (GMT) time measured in milliseconds since 0:00:00 on 1/1/70 (derived from the system time). + /// + /// The current UTC time in milliseconds. + public static double GetNow() + { + return NativeMethods.ucal_getNow(); + } + + public DateTime ToDateTime() + { + var dto = new DateTime(Year, + 1 + (int)Month, + DayOfMonth, + HourOfDay, + Minute, + Second, + Millisecond); + return dto; + } + + /// + /// Get the display name for a UCalendar's TimeZone. + /// + /// A display name is suitable for presentation to a user. + /// + /// The desired display name format + /// Formatted time zone name + public string GetTimeZoneDisplayName(UCalendarDisplayNameType type) + { + int length = NativeMethods.ucal_getTimeZoneDisplayName(_calendarHandle, type, _locale.Name, out string result, 60, out ErrorCode ec); + if (length >= 60) + { + NativeMethods.ucal_getTimeZoneDisplayName(_calendarHandle, type, _locale.Name, out result, length + 1, out ec); + } + ExceptionFromErrorCode.ThrowIfError(ec); + + return result; + } + + #region Properties + + /// + /// Gets or sets whether date/time interpretation is to be lenient. + /// + public bool Lenient + { + get + { + var result = NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.Lenient, out _); + return (result != 0); + } + set + { + NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.Lenient, value ? 1 : 0); + } + } + + /// + /// Gets or sets first day of week. + /// + public UCalendarDaysOfWeek FirstDayOfWeek + { + get + { + return (UCalendarDaysOfWeek)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.FirstDayOfWeek, out _); + } + set + { + NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.FirstDayOfWeek, (int)value); + } + } + + /// + /// Gets or sets minimal number of days in first week. + /// + public int MinimalDaysInFirstWeek + { + get + { + var result = NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.FirstDayOfWeek, out _); + return result; + } + set + { + NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.FirstDayOfWeek, value); + } + } + + /// + /// Gets or sets option for handling ambiguous wall time at time zone offset transitions. + /// + public UCalendarWallTimeOption RepeatedWallTimeOption + { + get + { + var result = (UCalendarWallTimeOption)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.RepeatedWallTime, out _); + return result; + } + set + { + NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.RepeatedWallTime, (int)value); + } + } + + /// + /// + /// + public UCalendarWallTimeOption SkippedWallTimeOption + { + get + { + var result = (UCalendarWallTimeOption)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.SkippedWallTime, out _); + return result; + } + set + { + NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.SkippedWallTime, (int)value); + } + } + + /// + /// Gets or sets era. + /// + public int Era + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Era, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Era, value); + } + } + + /// + /// Gets or sets year. + /// + public int Year + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Year, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Year, value); + } + } + + /// + /// Gets or sets motnth. + /// + public UCalendarMonths Month + { + get + { + return (UCalendarMonths)NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Month, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Month, (int)value); + } + } + + /// + /// Gets or sets week of year. + /// + public int WeekOfYear + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.WeekOfYear, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.WeekOfYear, value); + } + } + + /// + /// Gets or sets week of month. + /// + public int WeekOfMonth + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.WeekOfMonth, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.WeekOfMonth, value); + } + } + + /// + /// Gets or sets day of week. + /// + public int DayOfWeek + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfWeek, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.DayOfWeek, value); + } + } + + /// + /// Gets or sets day of month. + /// + public int DayOfMonth + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfMonth, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.DayOfMonth, value); + } + } + + /// + /// Gets or sets ordinal number of the day of the week within the current month. + /// + /// Together with the DAY_OF_WEEK field, this uniquely specifies a day within a month. + /// Unlike WEEK_OF_MONTH and WEEK_OF_YEAR, this field's value does not depend on getFirstDayOfWeek() + /// or getMinimalDaysInFirstWeek(). DAY_OF_MONTH 1 through 7 always correspond to DAY_OF_WEEK_IN_MONTH 1; + /// 8 through 15 correspond to DAY_OF_WEEK_IN_MONTH 2, and so on. DAY_OF_WEEK_IN_MONTH 0 indicates the week before DAY_OF_WEEK_IN_MONTH 1. + /// Negative values count back from the end of the month, so the last Sunday of a month is specified as DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1. + /// Because negative values count backward they will usually be aligned differently within the month than positive values. For example, + /// if a month has 31 days, DAY_OF_WEEK_IN_MONTH -1 will overlap DAY_OF_WEEK_IN_MONTH 5 and the end of 4. + /// + public int DayOfWeekInMonth + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfWeekInMonth, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.DayOfWeekInMonth, value); + } + } + + /// + /// Gets or sets day of year. + /// + public int DayOfYear + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfYear, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.DayOfYear, value); + } + } + + /// + /// Gets or seths whether the hour is before or after noon. + /// + public int AmPm + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.AmPm, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.AmPm, value); + } + } + + /// + /// Gets or sets hour in 12 hour based format. + /// + public int Hour + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Hour, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Hour, value); + } + } + + /// + /// Gets or sets hour in 24 hour based format. + /// + public int HourOfDay + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.HourOfDay, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.HourOfDay, value); + } + } + + /// + /// Gets or sets minute. + /// + public int Minute + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Minute, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Minute, value); + } + } + + /// + /// Gets or sets second. + /// + public int Second + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Second, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Second, value); + } + } + + /// + /// Gets or sets millisecond. + /// + public int Millisecond + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Millisecond, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Millisecond, value); + } + } + + /// + /// Gets or sets time zone ofset. + /// + public int ZoneOffset + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.ZoneOffset, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.ZoneOffset, value); + } + } + + /// + /// Gets or sets daylight savings time offset. + /// + public int DstOffset + { + get + { + return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DstOffset, out _); + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.DstOffset, value); + } + } + + /// + /// Calendar's locale. + /// + public Locale Locale + { + get => _locale; + } + + #endregion Properties + + + private void SetTimeZone(string id) + { + NativeMethods.ucal_setTimeZone(_calendarHandle, id, id.Length, out ErrorCode ec); + ExceptionFromErrorCode.ThrowIfError(ec); + } + + + #region IDisposable support + + /// + /// Dispose of managed/unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases the resources used by Calendar. + /// + /// true to release managed and unmanaged + /// resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (!_disposingValue) + { + if (disposing) + { + // Dispose managed state (managed objects), if any. + } + + _calendarHandle.Dispose(); + _disposingValue = true; + } + } + ~Calendar() + { + Dispose(false); + } + + #endregion + } +} diff --git a/source/icu.net/Calendar/GregorianCalendar.cs b/source/icu.net/Calendar/GregorianCalendar.cs new file mode 100644 index 00000000..25df2d11 --- /dev/null +++ b/source/icu.net/Calendar/GregorianCalendar.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Icu +{ + public class GregorianCalendar : Calendar + { + public GregorianCalendar() + : this(new Locale()) + { + } + + public GregorianCalendar(Locale locale) + :this(TimeZone.GetDefault(),locale) + { + } + + public GregorianCalendar(TimeZone timezone) + :this(timezone, new Locale()) + { + } + + public GregorianCalendar(TimeZone timezone, Locale locale) + { + _locale = locale; + _calendarHandle = NativeMethods.ucal_open(timezone.Id, + locale.Name, UCalendarType.Gregorian, out ErrorCode ec); + ExceptionFromErrorCode.ThrowIfError(ec); + } + + private GregorianCalendar(SafeCalendarHandle handle) + { + _calendarHandle = handle; + } + + public override Calendar Clone() + { + var handle = NativeMethods.ucal_clone(_calendarHandle, out ErrorCode status); + return new GregorianCalendar(handle); + } + + public override bool InDaylightTime() + { + return NativeMethods.ucal_inDaylightTime(_calendarHandle, out _); + } + } +} diff --git a/source/icu.net/NativeMethods/NativeMethods_Calendar.cs b/source/icu.net/NativeMethods/NativeMethods_Calendar.cs new file mode 100644 index 00000000..98fe800f --- /dev/null +++ b/source/icu.net/NativeMethods/NativeMethods_Calendar.cs @@ -0,0 +1,404 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Icu +{ + internal static partial class NativeMethods + { + private class CalendarMehodsContainer + { + + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_setTimeZoneDelegate( + Calendar.SafeCalendarHandle cal, + [MarshalAs(UnmanagedType.LPWStr)] string zoneID, + int len, + out ErrorCode ec); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate int ucal_getTimeZoneIdDelegate( + Calendar.SafeCalendarHandle cal, + IntPtr result, + int resultLength, + out ErrorCode ec); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate Calendar.SafeCalendarHandle ucal_openDelegate( + [MarshalAs(UnmanagedType.LPWStr)] string zoneID, + int len, + [MarshalAs(UnmanagedType.LPStr)] string locale, + Calendar.UCalendarType type, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_closeDelegate(IntPtr cal); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_addDelegate( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field, + int amount, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_rollDelegate( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field, + int amount, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate int ucal_getDelegate( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_clearDelegate( + Calendar.SafeCalendarHandle cal); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_clearFieldDelegate( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate Calendar.SafeCalendarHandle ucal_cloneDelegate( + Calendar.SafeCalendarHandle cal, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate int ucal_getAttributeDelegate( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarAttribute attribute, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate int ucal_getFieldDifferenceDelegate( + Calendar.SafeCalendarHandle cal, + double target, + Calendar.UCalendarDateFields field, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate double ucal_getMillisDelegate( + Calendar.SafeCalendarHandle cal, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate double ucal_getNowDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate int ucal_getTimeZoneDisplayNameDelegate( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDisplayNameType type, + [MarshalAs(UnmanagedType.LPStr)] string locale, + IntPtr result, + int resultLength, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate bool ucal_inDaylightTimeDelegate( + Calendar.SafeCalendarHandle cal, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_setDelegate( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field, + int value); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate bool ucal_isSetDelegate( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_setAttributeDelegate( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarAttribute attr, + int newValue); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_setDateTimeDelegate( + Calendar.SafeCalendarHandle cal, + int year, int month, int date, + out ErrorCode status); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal delegate void ucal_setMillisDelegate( + Calendar.SafeCalendarHandle cal, + double dateTime, + out ErrorCode status); + + + internal ucal_openDelegate ucal_open; + internal ucal_closeDelegate ucal_close; + internal ucal_setTimeZoneDelegate ucal_setTimeZone; + internal ucal_getTimeZoneIdDelegate ucal_getTimeZoneId; + internal ucal_addDelegate ucal_add; + internal ucal_rollDelegate ucal_roll; + internal ucal_getDelegate ucal_get; + internal ucal_clearDelegate ucal_clear; + internal ucal_clearFieldDelegate ucal_clearField; + internal ucal_cloneDelegate ucal_clone; + internal ucal_getAttributeDelegate ucal_getAttribute; + internal ucal_getFieldDifferenceDelegate ucal_getFieldDifference; + internal ucal_getMillisDelegate ucal_getMillis; + internal ucal_getNowDelegate ucal_getNow; + internal ucal_getTimeZoneDisplayNameDelegate ucal_getTimeZoneDisplayName; + internal ucal_inDaylightTimeDelegate ucal_inDaylightTime; + internal ucal_setDelegate ucal_set; + internal ucal_isSetDelegate ucal_isSet; + internal ucal_setAttributeDelegate ucal_setAttribute; + internal ucal_setDateTimeDelegate ucal_setDateTime; + internal ucal_setMillisDelegate ucal_setMillis; + } + + private static CalendarMehodsContainer _CalendarMethods; + + private static CalendarMehodsContainer CalendarMethods => + _CalendarMethods ?? + (_CalendarMethods = new CalendarMehodsContainer()); + + #region Calendar + + + public static void ucal_setTimeZone( + Calendar.SafeCalendarHandle cal, + string zoneID, + int len, + out ErrorCode ec) + { + if (CalendarMethods.ucal_setTimeZone == null) + CalendarMethods.ucal_setTimeZone = GetMethod(IcuI18NLibHandle, "ucal_setTimeZone"); + CalendarMethods.ucal_setTimeZone(cal, zoneID, len, out ec); + } + + public static int ucal_getTimeZoneId( + Calendar.SafeCalendarHandle cal, + out string result, + int resultLength, + out ErrorCode ec) + { + if (CalendarMethods.ucal_getTimeZoneId == null) + CalendarMethods.ucal_getTimeZoneId = GetMethod(IcuI18NLibHandle, "ucal_getTimeZoneID"); + + IntPtr outBuf = Marshal.AllocHGlobal(resultLength * sizeof(char)); + try + { + int length = CalendarMethods.ucal_getTimeZoneId(cal, outBuf, resultLength, out ec); + char[] buf = new char[Math.Min(resultLength, length)]; + Marshal.Copy(outBuf, buf, 0, buf.Length); + result = new string(buf); + return length; + } + finally + { + Marshal.FreeHGlobal(outBuf); + } + } + + public static Calendar.SafeCalendarHandle ucal_open( + string zoneID, + string locale, + Calendar.UCalendarType type, + out ErrorCode status) + { + if (CalendarMethods.ucal_open == null) + CalendarMethods.ucal_open = GetMethod(IcuI18NLibHandle, "ucal_open"); + return CalendarMethods.ucal_open(zoneID, zoneID.Length, locale, type, out status); + } + + public static void ucal_close(IntPtr cal) + { + if (CalendarMethods.ucal_close == null) + CalendarMethods.ucal_close = GetMethod(IcuI18NLibHandle, "ucal_close"); + CalendarMethods.ucal_close(cal); + } + + + public static void ucal_add( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field, + int amount, + out ErrorCode status) + { + if (CalendarMethods.ucal_add == null) + CalendarMethods.ucal_add = GetMethod(IcuI18NLibHandle, "ucal_add"); + CalendarMethods.ucal_add(cal, field, amount, out status); + } + public static void ucal_roll( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field, + int amount, + out ErrorCode status) + { + if (CalendarMethods.ucal_roll == null) + CalendarMethods.ucal_roll = GetMethod(IcuI18NLibHandle, "ucal_roll"); + CalendarMethods.ucal_roll(cal, field, amount, out status); + } + + public static int ucal_get( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field, + out ErrorCode status) + { + if (CalendarMethods.ucal_get == null) + CalendarMethods.ucal_get = GetMethod(IcuI18NLibHandle, "ucal_get"); + return CalendarMethods.ucal_get(cal, field, out status); + } + + public static int ucal_getAttribute( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarAttribute attribute, + out ErrorCode status) + { + if (CalendarMethods.ucal_getAttribute == null) + CalendarMethods.ucal_getAttribute = GetMethod(IcuI18NLibHandle, "ucal_getAttribute"); + return CalendarMethods.ucal_getAttribute(cal, attribute, out status); + } + + public static void ucal_clear( + Calendar.SafeCalendarHandle cal) + { + if (CalendarMethods.ucal_clear == null) + CalendarMethods.ucal_clear = GetMethod(IcuI18NLibHandle, "ucal_clear"); + CalendarMethods.ucal_clear(cal); + } + + public static void ucal_clearField( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field) + { + if (CalendarMethods.ucal_clearField == null) + CalendarMethods.ucal_clearField = GetMethod(IcuI18NLibHandle, "ucal_clearField"); + CalendarMethods.ucal_clearField(cal, field); + } + + public static Calendar.SafeCalendarHandle ucal_clone(Calendar.SafeCalendarHandle cal, out ErrorCode status) + { + if (CalendarMethods.ucal_clone == null) + CalendarMethods.ucal_clone = GetMethod(IcuI18NLibHandle, "ucal_clone"); + return CalendarMethods.ucal_clone(cal, out status); + } + + public static int ucal_getFieldDifference( + Calendar.SafeCalendarHandle cal, + double target, + Calendar.UCalendarDateFields field, + out ErrorCode status) + { + if (CalendarMethods.ucal_getFieldDifference == null) + CalendarMethods.ucal_getFieldDifference = GetMethod(IcuI18NLibHandle, "ucal_getFieldDifference"); + return CalendarMethods.ucal_getFieldDifference(cal, target, field, out status); + } + + public static double ucal_getMillis( + Calendar.SafeCalendarHandle cal, + out ErrorCode status) + { + if (CalendarMethods.ucal_getMillis == null) + CalendarMethods.ucal_getMillis = GetMethod(IcuI18NLibHandle, "ucal_getMillis"); + return CalendarMethods.ucal_getMillis(cal, out status); + } + + public static double ucal_getNow() + { + if (CalendarMethods.ucal_getNow == null) + CalendarMethods.ucal_getNow = GetMethod(IcuI18NLibHandle, "ucal_getNow"); + return CalendarMethods.ucal_getNow(); + } + + public static int ucal_getTimeZoneDisplayName( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDisplayNameType type, + string locale, + out string result, + int resultLength, + out ErrorCode status) + { + if (CalendarMethods.ucal_getTimeZoneDisplayName == null) + CalendarMethods.ucal_getTimeZoneDisplayName = GetMethod(IcuI18NLibHandle, "ucal_getTimeZoneDisplayName"); + + IntPtr outBuf = Marshal.AllocHGlobal(resultLength * sizeof(char)); + try + { + int length = CalendarMethods.ucal_getTimeZoneDisplayName(cal, type, locale, outBuf, resultLength, out status); + char[] buf = new char[Math.Min(resultLength, length)]; + Marshal.Copy(outBuf, buf, 0, buf.Length); + result = new string(buf); + return length; + } + finally + { + Marshal.FreeHGlobal(outBuf); + } + } + + public static bool ucal_inDaylightTime( + Calendar.SafeCalendarHandle cal, + out ErrorCode status) + { + if (CalendarMethods.ucal_inDaylightTime == null) + CalendarMethods.ucal_inDaylightTime = GetMethod(IcuI18NLibHandle, "ucal_inDaylightTime"); + return CalendarMethods.ucal_inDaylightTime(cal, out status); + } + + + public static void ucal_set( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field, + int value) + { + if (CalendarMethods.ucal_set == null) + CalendarMethods.ucal_set = GetMethod(IcuI18NLibHandle, "ucal_set"); + CalendarMethods.ucal_set(cal, field, value); + } + public static bool ucal_isSet( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarDateFields field) + { + if (CalendarMethods.ucal_isSet == null) + CalendarMethods.ucal_isSet = GetMethod(IcuI18NLibHandle, "ucal_isSet"); + return CalendarMethods.ucal_isSet(cal, field); + } + + public static void ucal_setAttribute( + Calendar.SafeCalendarHandle cal, + Calendar.UCalendarAttribute attr, + int newValue) + { + if (CalendarMethods.ucal_setAttribute == null) + CalendarMethods.ucal_setAttribute = GetMethod(IcuI18NLibHandle, "ucal_setAttribute"); + CalendarMethods.ucal_setAttribute(cal, attr, newValue); + } + + public static void ucal_setDateTime( + Calendar.SafeCalendarHandle cal, + int year, int month, int date, + out ErrorCode status) + { + if (CalendarMethods.ucal_setDateTime == null) + CalendarMethods.ucal_setDateTime = GetMethod(IcuI18NLibHandle, "ucal_setDateTime"); + CalendarMethods.ucal_setDateTime(cal, year, month, date, out status); + } + + public static void ucal_setMillis( + Calendar.SafeCalendarHandle cal, + double dateTime, + out ErrorCode status) + { + if (CalendarMethods.ucal_setMillis == null) + CalendarMethods.ucal_setMillis = GetMethod(IcuI18NLibHandle, "ucal_setMillis"); + CalendarMethods.ucal_setMillis(cal, dateTime, out status); + } + + #endregion + } +} From e4e20b1080355a49e25b394488aa0ff8c17ba45d Mon Sep 17 00:00:00 2001 From: j-troc Date: Wed, 17 Apr 2019 15:13:49 +0200 Subject: [PATCH 2/6] Fix review issues --- source/icu.net.tests/CalendarTests.cs | 508 +++++++++++------- source/icu.net/Calendar/Calendar.cs | 140 +++-- source/icu.net/Calendar/GregorianCalendar.cs | 15 +- .../NativeMethods/NativeMethods_Calendar.cs | 25 +- 4 files changed, 411 insertions(+), 277 deletions(-) diff --git a/source/icu.net.tests/CalendarTests.cs b/source/icu.net.tests/CalendarTests.cs index 4f2e0579..4321a79f 100644 --- a/source/icu.net.tests/CalendarTests.cs +++ b/source/icu.net.tests/CalendarTests.cs @@ -15,297 +15,400 @@ class CalendarTests public void GetTimeZoneDisplayNameTest() { var timezone = new TimeZone("AST"); - var cal = new GregorianCalendar(timezone); + using (var cal = new GregorianCalendar(timezone)) + { + var displayName = cal.GetTimeZoneDisplayName(Calendar.UCalendarDisplayNameType.Standard); - var displayName = cal.GetTimeZoneDisplayName(Calendar.UCalendarDisplayNameType.Standard); - - Assert.AreEqual("Alaska Standard Time", displayName); + Assert.AreEqual("Alaska Standard Time", displayName); + } } [Test] public void ClearTest() { - var cal = new GregorianCalendar(); - cal.Month = Calendar.UCalendarMonths.September; - cal.DayOfMonth = 4; + using (var cal = new GregorianCalendar()) + { + cal.Month = Calendar.UCalendarMonths.September; + cal.DayOfMonth = 4; - cal.Clear(); + cal.Clear(); - Assert.AreEqual(Calendar.UCalendarMonths.January, cal.Month); - Assert.AreEqual(1, cal.DayOfMonth); + Assert.AreEqual(Calendar.UCalendarMonths.January, cal.Month); + Assert.AreEqual(1, cal.DayOfMonth); + } } [Test] public void ClearFieldTest() { - var cal = new GregorianCalendar(); - cal.Month = Calendar.UCalendarMonths.September; + using (var cal = new GregorianCalendar()) + { + cal.Month = Calendar.UCalendarMonths.September; - cal.Clear(Calendar.UCalendarDateFields.Month); + cal.Clear(Calendar.UCalendarDateFields.Month); - Assert.AreEqual(Calendar.UCalendarMonths.January, cal.Month); + Assert.AreEqual(Calendar.UCalendarMonths.January, cal.Month); + } } [Test] public void CloneTest() { - var cal1 = new GregorianCalendar(); - - cal1.DayOfMonth = 5; - var cal2 = cal1.Clone(); - cal2.DayOfMonth = 10; - - Assert.AreEqual(5, cal1.DayOfMonth); + using (var cal1 = new GregorianCalendar()) + { + cal1.DayOfMonth = 5; + using (var cal2 = cal1.Clone()) + { + cal2.DayOfMonth = 10; + + Assert.AreEqual(5, cal1.DayOfMonth); + Assert.AreEqual(10, cal2.DayOfMonth); + } + } } [Test] public void RollTest() { - var cal = new GregorianCalendar(); - var startMonth = cal.Month; + using (var cal = new GregorianCalendar()) + { + var startMonth = cal.Month; - cal.Roll(Calendar.UCalendarDateFields.DayOfMonth, 100); + cal.Roll(Calendar.UCalendarDateFields.DayOfMonth, 100); - Assert.AreEqual(startMonth, cal.Month); + Assert.AreEqual(startMonth, cal.Month); + } } [Test] public void SetTest() { - var cal = new GregorianCalendar(new TimeZone("UTC")); - cal.Clear(); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.Clear(); - cal.Set(Calendar.UCalendarDateFields.DayOfYear, 2); + cal.Set(Calendar.UCalendarDateFields.DayOfYear, 2); - Assert.AreEqual(24 * 60 * 60 * 1000, cal.GetTime()); + Assert.AreEqual(24 * 60 * 60 * 1000, cal.GetTime()); + } + } + + [Test] + public void RollAddDifferenceTest() + { + var month = Calendar.UCalendarMonths.April; + int day = 30; + + using (Calendar cal1 = new GregorianCalendar(new TimeZone("UTC")), + cal2 = new GregorianCalendar(new TimeZone("UTC"))) + { + cal1.Month = month; + cal1.DayOfMonth = day; + + cal2.Month = month; + cal2.DayOfMonth = day; + + cal1.Add(Calendar.UCalendarDateFields.DayOfMonth, 1); + cal2.Roll(Calendar.UCalendarDateFields.DayOfMonth, 1); + + Assert.AreEqual(Calendar.UCalendarMonths.May,cal1.Month); + Assert.AreEqual(1, cal1.DayOfMonth); + + Assert.AreEqual(Calendar.UCalendarMonths.April, cal2.Month); + Assert.AreEqual(1, cal2.DayOfMonth); + } } [Test] public void GetTest() { - var cal = new GregorianCalendar(new TimeZone("UTC")); - var expected = 15; - cal.Set(Calendar.UCalendarDateFields.DayOfYear, expected); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + var expected = 15; + cal.Set(Calendar.UCalendarDateFields.DayOfYear, expected); - var result = cal.Get(Calendar.UCalendarDateFields.DayOfYear); + var result = cal.Get(Calendar.UCalendarDateFields.DayOfYear); - Assert.AreEqual(expected, result); + Assert.AreEqual(expected, result); + } } [Test] public void FieldDifferenceTest() { - var cal = new GregorianCalendar(); - var time = cal.GetTime(); + using (var cal = new GregorianCalendar()) + { + var time = cal.GetTime(); - cal.Add(Calendar.UCalendarDateFields.Hour, 2); - cal.Add(Calendar.UCalendarDateFields.Minute, 2); + cal.Add(Calendar.UCalendarDateFields.Hour, 2); + cal.Add(Calendar.UCalendarDateFields.Minute, 2); - var difference = cal.FieldDifference(time, Calendar.UCalendarDateFields.Minute); + var difference = cal.FieldDifference(time, Calendar.UCalendarDateFields.Minute); - Assert.AreEqual(time, cal.GetTime()); - Assert.AreEqual(-122, difference); + Assert.AreEqual(time, cal.GetTime()); + Assert.AreEqual(-122, difference); + } } [Test] public void IsSetTest() { - var cal = new GregorianCalendar(); - cal.Month = Calendar.UCalendarMonths.September; - cal.DayOfMonth = 4; - - var setBefore = cal.IsSet(Calendar.UCalendarDateFields.Month); - cal.Clear(); - var setAfter = cal.IsSet(Calendar.UCalendarDateFields.Month); - - Assert.AreEqual(true, setBefore); - Assert.AreEqual(false, setAfter); + using (var cal = new GregorianCalendar()) + { + cal.Month = Calendar.UCalendarMonths.September; + cal.DayOfMonth = 4; + + var setBefore = cal.IsSet(Calendar.UCalendarDateFields.Month); + cal.Clear(); + var setAfter = cal.IsSet(Calendar.UCalendarDateFields.Month); + + Assert.AreEqual(true, setBefore); + Assert.AreEqual(false, setAfter); + } } [Test] public void InDaylightTime() { - var cal = new GregorianCalendar(new TimeZone("Europe/Warsaw")); - - cal.Month = Calendar.UCalendarMonths.September; - cal.DayOfMonth = 1; + using (var cal = new GregorianCalendar(new TimeZone("Europe/Warsaw"))) + { + cal.Month = Calendar.UCalendarMonths.September; + cal.DayOfMonth = 1; - Assert.AreEqual(true, cal.InDaylightTime()); + Assert.AreEqual(true, cal.InDaylightTime()); + } } - + [Test] public void SetTimeTest() { - var cal = new GregorianCalendar(new TimeZone("UTC")); - cal.SetTime(0); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.SetTime(0); + + Assert.AreEqual(1970, cal.Year); + Assert.AreEqual(0, cal.Hour); + Assert.AreEqual(0, cal.Minute); + Assert.AreEqual(0, cal.Millisecond); + } + } + + [Test] + public void SetTimeDateTimeTest() + { + using (var cal = new GregorianCalendar()) + { + var dateTime = DateTime.Now; + cal.SetTime(dateTime); + + var result = cal.ToDateTime(); + + // Truncate submillisecond part + dateTime = dateTime.AddTicks(-(dateTime.Ticks % TimeSpan.TicksPerMillisecond)); + + Assert.AreEqual(dateTime, result); + } + } + + [Test] + public void SetTimeDateTimeTest2() + { + var timezones = TimeZone.GetTimeZones(); + using (var cal = new GregorianCalendar(new TimeZone("Etc/GMT-7"))) + { + var dateTime = DateTime.Now.ToUniversalTime(); + cal.SetTime(dateTime); - Assert.AreEqual(1970, cal.Year); - Assert.AreEqual(0, cal.Hour); - Assert.AreEqual(0, cal.Minute); - Assert.AreEqual(0, cal.Millisecond); + var result = cal.ToDateTime(); + + // Truncate submillisecond part + dateTime = dateTime.AddTicks(-(dateTime.Ticks % TimeSpan.TicksPerMillisecond)); + + dateTime = dateTime.AddHours(7); + + Assert.AreEqual(dateTime, result); + } } [Test] public void ToDateTimeTest() { - var cal = new GregorianCalendar(); - var datetime = cal.ToDateTime(); - - Assert.AreEqual(cal.Year, datetime.Year); - Assert.AreEqual((int)cal.Month + 1, datetime.Month); - Assert.AreEqual(cal.DayOfMonth, datetime.Day); - Assert.AreEqual(cal.HourOfDay, datetime.Hour); - Assert.AreEqual(cal.Minute, datetime.Minute); - Assert.AreEqual(cal.Second, datetime.Second); - Assert.AreEqual(cal.Millisecond, datetime.Millisecond); + using (var cal = new GregorianCalendar()) + { + var datetime = cal.ToDateTime(); + + Assert.AreEqual(cal.Year, datetime.Year); + Assert.AreEqual((int)cal.Month + 1, datetime.Month); + Assert.AreEqual(cal.DayOfMonth, datetime.Day); + Assert.AreEqual(cal.HourOfDay, datetime.Hour); + Assert.AreEqual(cal.Minute, datetime.Minute); + Assert.AreEqual(cal.Second, datetime.Second); + Assert.AreEqual(cal.Millisecond, datetime.Millisecond); + } } [Test] public void SetTimeZoneTest() { var expected = new TimeZone("AST"); - var cal = new GregorianCalendar(new TimeZone("UTC")); - cal.SetTimeZone(expected); - var result = cal.GetTimeZone(); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.SetTimeZone(expected); + var result = cal.GetTimeZone(); - Assert.AreEqual(expected.Id, result.Id); + Assert.AreEqual(expected.Id, result.Id); + } } [Test] public void FirstDayOfWeekTest() { - var cal = new GregorianCalendar(new TimeZone("UTC")); - var newDay = Calendar.UCalendarDaysOfWeek.Thursday; + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + var newDay = Calendar.UCalendarDaysOfWeek.Thursday; - var val0 = cal.FirstDayOfWeek; - cal.FirstDayOfWeek = newDay; - var val1 = cal.FirstDayOfWeek; + var val0 = cal.FirstDayOfWeek; + cal.FirstDayOfWeek = newDay; + var val1 = cal.FirstDayOfWeek; - Assert.AreEqual(Calendar.UCalendarDaysOfWeek.Sunday, val0); - Assert.AreEqual(newDay, val1); + Assert.AreEqual(Calendar.UCalendarDaysOfWeek.Sunday, val0); + Assert.AreEqual(newDay, val1); + } } [Test] public void WeekOfYearTest() { - var cal = new GregorianCalendar(new TimeZone("UTC")); - cal.Clear(); - cal.DayOfMonth = 4; - var newDay = Calendar.UCalendarDaysOfWeek.Thursday; + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.Clear(); + cal.DayOfMonth = 4; + var newDay = Calendar.UCalendarDaysOfWeek.Thursday; - var val0 = cal.WeekOfYear; - cal.FirstDayOfWeek = newDay; - var val1 = cal.WeekOfYear; + var val0 = cal.WeekOfYear; + cal.FirstDayOfWeek = newDay; + var val1 = cal.WeekOfYear; - Assert.AreEqual(2, val0); - Assert.AreEqual(1, val1); + Assert.AreEqual(2, val0); + Assert.AreEqual(1, val1); + } } [Test] public void MinimalDaysInFirstWeekTest() { - var cal = new GregorianCalendar(new TimeZone("UTC")); - cal.Clear(); - cal.DayOfMonth = 4; - var newMinimum = 5; - - var val0 = cal.WeekOfYear; - cal.MinimalDaysInFirstWeek = newMinimum; - var val1 = cal.WeekOfYear; - - Assert.AreEqual(2, val0); - Assert.AreEqual(1, val1); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.Clear(); + cal.DayOfMonth = 4; + var newMinimum = 5; + + var val0 = cal.WeekOfYear; + cal.MinimalDaysInFirstWeek = newMinimum; + var val1 = cal.WeekOfYear; + + Assert.AreEqual(2, val0); + Assert.AreEqual(1, val1); + } } [Test] public void SkippedWallTimeTest() { - var cal = new GregorianCalendar(new TimeZone("America/New_York")); - cal.Year = 2011; - cal.HourOfDay = 0; - cal.Minute = 0; - cal.Month = Calendar.UCalendarMonths.March; - cal.DayOfMonth = 13; - - cal.SkippedWallTimeOption = Calendar.UCalendarWallTimeOption.WalltimeFirst; - cal.Minute = 30; - cal.HourOfDay = 2; - var hour = cal.HourOfDay; - var minute = cal.Minute; - - Assert.AreEqual(1, hour); - Assert.AreEqual(30, minute); + using (var cal = new GregorianCalendar(new TimeZone("America/New_York"))) + { + cal.Year = 2011; + cal.Month = Calendar.UCalendarMonths.March; + cal.DayOfMonth = 13; + cal.HourOfDay = 0; + cal.Minute = 0; + + cal.SkippedWallTimeOption = Calendar.UCalendarWallTimeOption.WalltimeFirst; + cal.HourOfDay = 2; + cal.Minute = 30; + var hour = cal.HourOfDay; + var minute = cal.Minute; + + Assert.AreEqual(1, hour); + Assert.AreEqual(30, minute); + } } [Test] public void RepeatedWallTimeTest() { - var cal = new GregorianCalendar(new TimeZone("America/New_York")); - cal.Year = 2011; - cal.HourOfDay = 0; - cal.Minute = 0; - cal.Month = Calendar.UCalendarMonths.November; - cal.DayOfMonth = 6; - - cal.RepeatedWallTimeOption = Calendar.UCalendarWallTimeOption.WalltimeFirst; - cal.Minute = 30; - cal.HourOfDay = 1; - cal.Add(Calendar.UCalendarDateFields.Minute, 60); - var hour = cal.HourOfDay; - var minute = cal.Minute; - - Assert.AreEqual(1, hour); - Assert.AreEqual(30, minute); + using (var cal = new GregorianCalendar(new TimeZone("America/New_York"))) + { + cal.Year = 2011; + cal.Month = Calendar.UCalendarMonths.November; + cal.DayOfMonth = 6; + cal.HourOfDay = 0; + cal.Minute = 0; + + cal.RepeatedWallTimeOption = Calendar.UCalendarWallTimeOption.WalltimeFirst; + cal.HourOfDay = 1; + cal.Minute = 30; + cal.Add(Calendar.UCalendarDateFields.Minute, 60); + var hour = cal.HourOfDay; + var minute = cal.Minute; + + Assert.AreEqual(1, hour); + Assert.AreEqual(30, minute); + } } [Test] public void LenientTest_ThrowsArgumentException() { - - var cal = new GregorianCalendar(new TimeZone("America/New_York")); - cal.Year = 2011; - cal.HourOfDay = 0; - cal.Minute = 0; - cal.Month = Calendar.UCalendarMonths.March; - cal.DayOfMonth = 13; - - cal.Lenient = false; - cal.SkippedWallTimeOption = Calendar.UCalendarWallTimeOption.WalltimeFirst; - cal.Minute = 30; - cal.HourOfDay = 2; - - Assert.Throws(() => cal.GetTime()); + using (var cal = new GregorianCalendar(new TimeZone("America/New_York"))) + { + cal.Year = 2011; + cal.Month = Calendar.UCalendarMonths.March; + cal.DayOfMonth = 13; + cal.HourOfDay = 0; + cal.Minute = 0; + + cal.Lenient = false; + cal.SkippedWallTimeOption = Calendar.UCalendarWallTimeOption.WalltimeFirst; + cal.Minute = 30; + cal.HourOfDay = 2; + + Assert.Throws(() => cal.GetTime()); + } } [Test] public void WeekOfMonthTest() { - var cal = new GregorianCalendar(new TimeZone("UTC")); - cal.Clear(); - cal.DayOfMonth = 4; - var newMinimum = 5; - - var val0 = cal.WeekOfMonth; - cal.MinimalDaysInFirstWeek = newMinimum; - var val1 = cal.WeekOfMonth; - - Assert.AreEqual(2, val0); - Assert.AreEqual(1, val1); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.Clear(); + cal.DayOfMonth = 4; + var newMinimum = 5; + + var val0 = cal.WeekOfMonth; + cal.MinimalDaysInFirstWeek = newMinimum; + var val1 = cal.WeekOfMonth; + + Assert.AreEqual(2, val0); + Assert.AreEqual(1, val1); + } } [Test] public void EraTest() { - var cal = new GregorianCalendar(new TimeZone("UTC")); - - var era1 = cal.Era; - cal.Year = -1; - var era0 = cal.Era; - - Assert.AreEqual(1, era1); - Assert.AreEqual(0, era0); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + var era1 = cal.Era; + cal.Year = -1; + var era0 = cal.Era; + + Assert.AreEqual(1, era1); + Assert.AreEqual(0, era0); + } } [Test] @@ -313,11 +416,13 @@ public void ZoneOffsetTest() { var expected = 60 * 60 * 1000; var zone = new TimeZone("Europe/Paris"); - var cal = new GregorianCalendar(zone); - var offset = cal.ZoneOffset; + using (var cal = new GregorianCalendar(zone)) + { + var offset = cal.ZoneOffset; - Assert.AreEqual(expected, offset); + Assert.AreEqual(expected, offset); + } } [Test] @@ -327,62 +432,67 @@ public void DstOffsetTest() var expected1 = 0; var zone = new TimeZone("Europe/Paris"); - var cal = new GregorianCalendar(zone); - cal.Month = Calendar.UCalendarMonths.July; - cal.DayOfMonth = 20; - var offset0 = cal.DstOffset; - cal.Month = Calendar.UCalendarMonths.January; - var offset1 = cal.DstOffset; + using (var cal = new GregorianCalendar(zone)) + { + cal.Month = Calendar.UCalendarMonths.July; + cal.DayOfMonth = 20; - Assert.AreEqual(expected0, offset0); - Assert.AreEqual(expected1, offset1); + var offset0 = cal.DstOffset; + cal.Month = Calendar.UCalendarMonths.January; + var offset1 = cal.DstOffset; + Assert.AreEqual(expected0, offset0); + Assert.AreEqual(expected1, offset1); + } } [Test] public void AmPmTest() { - var cal = new GregorianCalendar(new TimeZone("UTC")); - - cal.HourOfDay = 3; - var val0 = cal.AmPm; - cal.HourOfDay = 14; - var val1 = cal.AmPm; - - Assert.AreEqual(0, val0); - Assert.AreEqual(1, val1); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.HourOfDay = 3; + var val0 = cal.AmPm; + cal.HourOfDay = 14; + var val1 = cal.AmPm; + + Assert.AreEqual(Calendar.UCalendarAMPMs.Am, val0); + Assert.AreEqual(Calendar.UCalendarAMPMs.Pm, val1); + } } [Test] - public void SetTimeZone2Test() { var winId = "Romance Standard Time"; var expected = "Europe/Paris"; var timezone = TimeZoneInfo.FindSystemTimeZoneById(winId); - var cal = new GregorianCalendar(new TimeZone("UTC")); - cal.SetTimeZone(timezone); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.SetTimeZone(timezone); - var tz = cal.GetTimeZone(); + var tz = cal.GetTimeZone(); - Assert.AreEqual(expected, tz.Id); + Assert.AreEqual(expected, tz.Id); + } } [Test] - public void GetTimeZoneTest() + public void GetTimeZoneInfoTest() { var timezone = new TimeZone("Europe/Zagreb"); var expected = "Central European Standard Time"; - var cal = new GregorianCalendar(timezone); + using (var cal = new GregorianCalendar(timezone)) + { + var tz = cal.GetTimeZoneInfo(); - var tz = cal.GetTimeZoneInfo(); - - Assert.AreEqual(expected, tz.Id); + Assert.AreEqual(expected, tz.Id); + } } - + } } diff --git a/source/icu.net/Calendar/Calendar.cs b/source/icu.net/Calendar/Calendar.cs index c655ea88..139c9e38 100644 --- a/source/icu.net/Calendar/Calendar.cs +++ b/source/icu.net/Calendar/Calendar.cs @@ -107,7 +107,7 @@ public enum UCalendarAMPMs Am, Pm }; - + internal protected sealed class SafeCalendarHandle : SafeHandle { public SafeCalendarHandle() : @@ -150,11 +150,11 @@ protected override void Dispose(bool disposing) } } - private bool _disposingValue; // To detect redundant calls + private bool _isDisposed; // To detect redundant calls protected SafeCalendarHandle _calendarHandle = default(SafeCalendarHandle); protected Locale _locale; - + /// /// Gets this Calendar's time as milliseconds. /// @@ -186,21 +186,23 @@ public void SetTime(double date) /// /// Sets this Calendar's current time with the given date. - ///The time specified should be in non-local UTC(GMT) time. + /// Time will be set to matching time in calendar's timezone. /// - /// The given date in UTC (GMT) time. + /// The given date public void SetTime(DateTime dateTime) { - Year = dateTime.Year; - Month = (Calendar.UCalendarMonths)(dateTime.Month - 1); - DayOfMonth = dateTime.Day; - HourOfDay = dateTime.Hour; - Minute = dateTime.Minute; - Second = dateTime.Second; - Millisecond = dateTime.Millisecond; + var universalTime = dateTime.ToUniversalTime(); + + Year = universalTime.Year; + Month = (Calendar.UCalendarMonths)(universalTime.Month - 1); + DayOfMonth = universalTime.Day; + HourOfDay = universalTime.Hour; + Minute = universalTime.Minute; + Second = universalTime.Second; + Millisecond = universalTime.Millisecond; - //correct for utc - Add(UCalendarDateFields.Millisecond, ZoneOffset); + // Offset to calendars local timezone + Add(UCalendarDateFields.Millisecond, ZoneOffset+DstOffset); } /// @@ -343,7 +345,7 @@ public TimeZone GetTimeZone() if (length >= 32) { ec = ErrorCode.NoErrors; - NativeMethods.ucal_getTimeZoneId(_calendarHandle, out result, length+1, out ec); + NativeMethods.ucal_getTimeZoneId(_calendarHandle, out result, length + 1, out ec); } ExceptionFromErrorCode.ThrowIfError(ec); return new TimeZone(result); @@ -359,11 +361,11 @@ public TimeZoneInfo GetTimeZoneInfo() var timeZoneInfo = TimeZoneInfo.GetSystemTimeZones().FirstOrDefault(zone => zone.Id == id); - if(timeZoneInfo != null) + if (timeZoneInfo != null) { return timeZoneInfo; } - + string winid = TimeZone.GetWindowsId(id); if (!string.IsNullOrWhiteSpace(winid)) @@ -406,14 +408,11 @@ public DateTime ToDateTime() /// Formatted time zone name public string GetTimeZoneDisplayName(UCalendarDisplayNameType type) { - int length = NativeMethods.ucal_getTimeZoneDisplayName(_calendarHandle, type, _locale.Name, out string result, 60, out ErrorCode ec); - if (length >= 60) + return NativeMethods.GetUnicodeString((ptr, length) => { - NativeMethods.ucal_getTimeZoneDisplayName(_calendarHandle, type, _locale.Name, out result, length + 1, out ec); - } - ExceptionFromErrorCode.ThrowIfError(ec); - - return result; + length = NativeMethods.ucal_getTimeZoneDisplayName(_calendarHandle, type, _locale.Name, ptr, length, out ErrorCode status); + return new Tuple(status, length); + }, 255); } #region Properties @@ -425,7 +424,7 @@ public bool Lenient { get { - var result = NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.Lenient, out _); + var result = NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.Lenient); return (result != 0); } set @@ -441,7 +440,7 @@ public UCalendarDaysOfWeek FirstDayOfWeek { get { - return (UCalendarDaysOfWeek)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.FirstDayOfWeek, out _); + return (UCalendarDaysOfWeek)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.FirstDayOfWeek); } set { @@ -456,12 +455,12 @@ public int MinimalDaysInFirstWeek { get { - var result = NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.FirstDayOfWeek, out _); + var result = NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.MinimalDaysInFirstWeek); return result; } set { - NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.FirstDayOfWeek, value); + NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.MinimalDaysInFirstWeek, value); } } @@ -472,7 +471,8 @@ public UCalendarWallTimeOption RepeatedWallTimeOption { get { - var result = (UCalendarWallTimeOption)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.RepeatedWallTime, out _); + var result = (UCalendarWallTimeOption)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.RepeatedWallTime); + return result; } set @@ -488,7 +488,8 @@ public UCalendarWallTimeOption SkippedWallTimeOption { get { - var result = (UCalendarWallTimeOption)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.SkippedWallTime, out _); + var result = (UCalendarWallTimeOption)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.SkippedWallTime); + return result; } set @@ -504,7 +505,9 @@ public int Era { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Era, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Era, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -519,7 +522,9 @@ public int Year { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Year, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Year, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -534,7 +539,9 @@ public UCalendarMonths Month { get { - return (UCalendarMonths)NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Month, out _); + var result = (UCalendarMonths)NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Month, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -549,7 +556,9 @@ public int WeekOfYear { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.WeekOfYear, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.WeekOfYear, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -564,7 +573,9 @@ public int WeekOfMonth { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.WeekOfMonth, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.WeekOfMonth, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -579,7 +590,9 @@ public int DayOfWeek { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfWeek, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfWeek, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -594,7 +607,9 @@ public int DayOfMonth { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfMonth, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfMonth, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -617,7 +632,9 @@ public int DayOfWeekInMonth { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfWeekInMonth, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfWeekInMonth, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -632,7 +649,9 @@ public int DayOfYear { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfYear, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfYear, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -643,15 +662,17 @@ public int DayOfYear /// /// Gets or seths whether the hour is before or after noon. /// - public int AmPm + public UCalendarAMPMs AmPm { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.AmPm, out _); + var result = (UCalendarAMPMs)NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.AmPm, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { - NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.AmPm, value); + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.AmPm, (int)value); } } @@ -662,7 +683,9 @@ public int Hour { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Hour, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Hour, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -677,7 +700,9 @@ public int HourOfDay { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.HourOfDay, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.HourOfDay, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -692,7 +717,9 @@ public int Minute { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Minute, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Minute, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -707,7 +734,9 @@ public int Second { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Second, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Second, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -722,7 +751,9 @@ public int Millisecond { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Millisecond, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Millisecond, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -737,7 +768,9 @@ public int ZoneOffset { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.ZoneOffset, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.ZoneOffset, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -752,7 +785,9 @@ public int DstOffset { get { - return NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DstOffset, out _); + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DstOffset, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; } set { @@ -796,15 +831,14 @@ public void Dispose() /// resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { - if (!_disposingValue) + if (!_isDisposed) { if (disposing) { - // Dispose managed state (managed objects), if any. + _calendarHandle.Dispose(); } - _calendarHandle.Dispose(); - _disposingValue = true; + _isDisposed = true; } } ~Calendar() diff --git a/source/icu.net/Calendar/GregorianCalendar.cs b/source/icu.net/Calendar/GregorianCalendar.cs index 25df2d11..3bba54f9 100644 --- a/source/icu.net/Calendar/GregorianCalendar.cs +++ b/source/icu.net/Calendar/GregorianCalendar.cs @@ -25,8 +25,8 @@ public GregorianCalendar(TimeZone timezone, Locale locale) { _locale = locale; _calendarHandle = NativeMethods.ucal_open(timezone.Id, - locale.Name, UCalendarType.Gregorian, out ErrorCode ec); - ExceptionFromErrorCode.ThrowIfError(ec); + locale.Name, UCalendarType.Gregorian, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); } private GregorianCalendar(SafeCalendarHandle handle) @@ -36,13 +36,18 @@ private GregorianCalendar(SafeCalendarHandle handle) public override Calendar Clone() { - var handle = NativeMethods.ucal_clone(_calendarHandle, out ErrorCode status); - return new GregorianCalendar(handle); + var handle = NativeMethods.ucal_clone(_calendarHandle, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + var calendar = new GregorianCalendar(handle); + calendar._locale = _locale; + return calendar; } public override bool InDaylightTime() { - return NativeMethods.ucal_inDaylightTime(_calendarHandle, out _); + bool isDaylightTime = NativeMethods.ucal_inDaylightTime(_calendarHandle, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return isDaylightTime; } } } diff --git a/source/icu.net/NativeMethods/NativeMethods_Calendar.cs b/source/icu.net/NativeMethods/NativeMethods_Calendar.cs index 98fe800f..12451b4e 100644 --- a/source/icu.net/NativeMethods/NativeMethods_Calendar.cs +++ b/source/icu.net/NativeMethods/NativeMethods_Calendar.cs @@ -75,8 +75,7 @@ internal delegate Calendar.SafeCalendarHandle ucal_cloneDelegate( [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] internal delegate int ucal_getAttributeDelegate( Calendar.SafeCalendarHandle cal, - Calendar.UCalendarAttribute attribute, - out ErrorCode status); + Calendar.UCalendarAttribute attribute); [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] internal delegate int ucal_getFieldDifferenceDelegate( @@ -256,12 +255,11 @@ public static int ucal_get( public static int ucal_getAttribute( Calendar.SafeCalendarHandle cal, - Calendar.UCalendarAttribute attribute, - out ErrorCode status) + Calendar.UCalendarAttribute attribute) { if (CalendarMethods.ucal_getAttribute == null) CalendarMethods.ucal_getAttribute = GetMethod(IcuI18NLibHandle, "ucal_getAttribute"); - return CalendarMethods.ucal_getAttribute(cal, attribute, out status); + return CalendarMethods.ucal_getAttribute(cal, attribute); } public static void ucal_clear( @@ -319,26 +317,13 @@ public static int ucal_getTimeZoneDisplayName( Calendar.SafeCalendarHandle cal, Calendar.UCalendarDisplayNameType type, string locale, - out string result, + IntPtr result, int resultLength, out ErrorCode status) { if (CalendarMethods.ucal_getTimeZoneDisplayName == null) CalendarMethods.ucal_getTimeZoneDisplayName = GetMethod(IcuI18NLibHandle, "ucal_getTimeZoneDisplayName"); - - IntPtr outBuf = Marshal.AllocHGlobal(resultLength * sizeof(char)); - try - { - int length = CalendarMethods.ucal_getTimeZoneDisplayName(cal, type, locale, outBuf, resultLength, out status); - char[] buf = new char[Math.Min(resultLength, length)]; - Marshal.Copy(outBuf, buf, 0, buf.Length); - result = new string(buf); - return length; - } - finally - { - Marshal.FreeHGlobal(outBuf); - } + return CalendarMethods.ucal_getTimeZoneDisplayName(cal, type, locale, result, resultLength, out status); } public static bool ucal_inDaylightTime( From 847f80d678625b17d6681cf28dafe320eea0fdec Mon Sep 17 00:00:00 2001 From: j-troc Date: Wed, 17 Apr 2019 19:36:38 +0200 Subject: [PATCH 3/6] Fix tests errors --- source/icu.net.tests/CalendarTests.cs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/source/icu.net.tests/CalendarTests.cs b/source/icu.net.tests/CalendarTests.cs index 4321a79f..1bbee80c 100644 --- a/source/icu.net.tests/CalendarTests.cs +++ b/source/icu.net.tests/CalendarTests.cs @@ -465,9 +465,16 @@ public void AmPmTest() [Test] public void SetTimeZone2Test() { + var tzdbId = "Europe/Paris"; var winId = "Romance Standard Time"; - var expected = "Europe/Paris"; - var timezone = TimeZoneInfo.FindSystemTimeZoneById(winId); + + var timezones = TimeZoneInfo.GetSystemTimeZones(); + + var timezone = timezones.FirstOrDefault(tzi => tzi.Id == tzdbId); + if(timezone==null) + { + timezone = timezones.First(tzi => tzi.Id == winId); + } using (var cal = new GregorianCalendar(new TimeZone("UTC"))) { @@ -475,21 +482,23 @@ public void SetTimeZone2Test() var tz = cal.GetTimeZone(); - Assert.AreEqual(expected, tz.Id); + Assert.AreEqual(tzdbId, tz.Id); } } [Test] public void GetTimeZoneInfoTest() { - var timezone = new TimeZone("Europe/Zagreb"); - var expected = "Central European Standard Time"; + var tzdbId = "Europe/Zagreb"; + var winId = "Central European Standard Time"; + + var timezone = new TimeZone(tzdbId); using (var cal = new GregorianCalendar(timezone)) { - var tz = cal.GetTimeZoneInfo(); + var result = cal.GetTimeZoneInfo(); - Assert.AreEqual(expected, tz.Id); + Assert.IsTrue(result.Id == winId || result.Id == tzdbId); } } From b2a57eb425aa504ef85ac17802cf3980a36c346a Mon Sep 17 00:00:00 2001 From: j-troc Date: Fri, 19 Apr 2019 17:40:40 +0200 Subject: [PATCH 4/6] fix calendar errors --- source/icu.net/Calendar/Calendar.cs | 20 +++++++------------ .../NativeMethods/NativeMethods_Calendar.cs | 16 ++------------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/source/icu.net/Calendar/Calendar.cs b/source/icu.net/Calendar/Calendar.cs index 139c9e38..3a664b9c 100644 --- a/source/icu.net/Calendar/Calendar.cs +++ b/source/icu.net/Calendar/Calendar.cs @@ -320,17 +320,13 @@ public void SetTimeZone(TimeZone timezone) /// /// Sets the calendar's time zone to be equivalent to the one passed in. /// - /// The given time zone info. + /// The given time zone info. public void SetTimeZone(TimeZoneInfo timeZoneInfo) { var id = timeZoneInfo.Id; - var converted = TimeZone.GetIdForWindowsId(id, _locale?.Country); - - if (!string.IsNullOrWhiteSpace(converted)) - { - id = converted; - } + if(!TimeZone.GetTimeZones().Any(tz=>tz.Id == id)) + id = TimeZone.GetIdForWindowsId(id, _locale?.Country); SetTimeZone(id); } @@ -341,13 +337,11 @@ public void SetTimeZone(TimeZoneInfo timeZoneInfo) /// Time zone set for this calendar. public TimeZone GetTimeZone() { - int length = NativeMethods.ucal_getTimeZoneId(_calendarHandle, out string result, 32, out ErrorCode ec); - if (length >= 32) + string result = NativeMethods.GetUnicodeString((ptr, length) => { - ec = ErrorCode.NoErrors; - NativeMethods.ucal_getTimeZoneId(_calendarHandle, out result, length + 1, out ec); - } - ExceptionFromErrorCode.ThrowIfError(ec); + length = NativeMethods.ucal_getTimeZoneId(_calendarHandle, ptr, length, out ErrorCode status); + return new Tuple(status, length); + }, 255); return new TimeZone(result); } diff --git a/source/icu.net/NativeMethods/NativeMethods_Calendar.cs b/source/icu.net/NativeMethods/NativeMethods_Calendar.cs index 12451b4e..1bf037db 100644 --- a/source/icu.net/NativeMethods/NativeMethods_Calendar.cs +++ b/source/icu.net/NativeMethods/NativeMethods_Calendar.cs @@ -181,26 +181,14 @@ public static void ucal_setTimeZone( public static int ucal_getTimeZoneId( Calendar.SafeCalendarHandle cal, - out string result, + IntPtr result, int resultLength, out ErrorCode ec) { if (CalendarMethods.ucal_getTimeZoneId == null) CalendarMethods.ucal_getTimeZoneId = GetMethod(IcuI18NLibHandle, "ucal_getTimeZoneID"); - IntPtr outBuf = Marshal.AllocHGlobal(resultLength * sizeof(char)); - try - { - int length = CalendarMethods.ucal_getTimeZoneId(cal, outBuf, resultLength, out ec); - char[] buf = new char[Math.Min(resultLength, length)]; - Marshal.Copy(outBuf, buf, 0, buf.Length); - result = new string(buf); - return length; - } - finally - { - Marshal.FreeHGlobal(outBuf); - } + return CalendarMethods.ucal_getTimeZoneId(cal, result, resultLength, out ec); } public static Calendar.SafeCalendarHandle ucal_open( From e1a8372030f6541122356c88b9c410786031a8f4 Mon Sep 17 00:00:00 2001 From: Jakub Troc Date: Tue, 25 Feb 2020 16:37:49 +0100 Subject: [PATCH 5/6] Fix calendar tests --- source/icu.net.tests/CalendarTests.cs | 150 +++++++++++++------------- 1 file changed, 72 insertions(+), 78 deletions(-) diff --git a/source/icu.net.tests/CalendarTests.cs b/source/icu.net.tests/CalendarTests.cs index 1bbee80c..d17f52a6 100644 --- a/source/icu.net.tests/CalendarTests.cs +++ b/source/icu.net.tests/CalendarTests.cs @@ -111,7 +111,7 @@ public void RollAddDifferenceTest() cal1.Add(Calendar.UCalendarDateFields.DayOfMonth, 1); cal2.Roll(Calendar.UCalendarDateFields.DayOfMonth, 1); - Assert.AreEqual(Calendar.UCalendarMonths.May,cal1.Month); + Assert.AreEqual(Calendar.UCalendarMonths.May, cal1.Month); Assert.AreEqual(1, cal1.DayOfMonth); Assert.AreEqual(Calendar.UCalendarMonths.April, cal2.Month); @@ -205,7 +205,7 @@ public void SetTimeDateTimeTest() // Truncate submillisecond part dateTime = dateTime.AddTicks(-(dateTime.Ticks % TimeSpan.TicksPerMillisecond)); - + Assert.AreEqual(dateTime, result); } } @@ -261,56 +261,43 @@ public void SetTimeZoneTest() } } - [Test] - public void FirstDayOfWeekTest() + [TestCase(Calendar.UCalendarDaysOfWeek.Sunday, ExpectedResult = Calendar.UCalendarDaysOfWeek.Sunday)] + [TestCase(Calendar.UCalendarDaysOfWeek.Thursday, ExpectedResult = Calendar.UCalendarDaysOfWeek.Thursday)] + public Calendar.UCalendarDaysOfWeek FirstDayOfWeekTest(Calendar.UCalendarDaysOfWeek firstDayOfWeek) { using (var cal = new GregorianCalendar(new TimeZone("UTC"))) { - var newDay = Calendar.UCalendarDaysOfWeek.Thursday; - - var val0 = cal.FirstDayOfWeek; - cal.FirstDayOfWeek = newDay; - var val1 = cal.FirstDayOfWeek; - - Assert.AreEqual(Calendar.UCalendarDaysOfWeek.Sunday, val0); - Assert.AreEqual(newDay, val1); + cal.FirstDayOfWeek = firstDayOfWeek; + return cal.FirstDayOfWeek; } } + [TestCase(Calendar.UCalendarDaysOfWeek.Sunday, ExpectedResult = 2)] + [TestCase(Calendar.UCalendarDaysOfWeek.Thursday, ExpectedResult = 1)] [Test] - public void WeekOfYearTest() + public int WeekOfYearTest(Calendar.UCalendarDaysOfWeek firstDayOfWeek) { using (var cal = new GregorianCalendar(new TimeZone("UTC"))) { cal.Clear(); cal.DayOfMonth = 4; - var newDay = Calendar.UCalendarDaysOfWeek.Thursday; - - var val0 = cal.WeekOfYear; - cal.FirstDayOfWeek = newDay; - var val1 = cal.WeekOfYear; - - Assert.AreEqual(2, val0); - Assert.AreEqual(1, val1); + cal.FirstDayOfWeek = firstDayOfWeek; + return cal.WeekOfYear; } } - [Test] - public void MinimalDaysInFirstWeekTest() + [TestCase(5, ExpectedResult = 1)] + [TestCase(1, ExpectedResult = 2)] + public int MinimalDaysInFirstWeekTest(int minimumDaysInFirstWeek) { using (var cal = new GregorianCalendar(new TimeZone("UTC"))) { cal.Clear(); cal.DayOfMonth = 4; - var newMinimum = 5; - - var val0 = cal.WeekOfYear; - cal.MinimalDaysInFirstWeek = newMinimum; - var val1 = cal.WeekOfYear; - Assert.AreEqual(2, val0); - Assert.AreEqual(1, val1); + cal.MinimalDaysInFirstWeek = minimumDaysInFirstWeek; + return cal.WeekOfYear; } } @@ -379,35 +366,28 @@ public void LenientTest_ThrowsArgumentException() } } - [Test] - public void WeekOfMonthTest() + [TestCase(5, ExpectedResult = 1)] + [TestCase(1, ExpectedResult = 2)] + public int WeekOfMonthTest(int minimumDaysInFirstWeek) { using (var cal = new GregorianCalendar(new TimeZone("UTC"))) { cal.Clear(); cal.DayOfMonth = 4; - var newMinimum = 5; - - var val0 = cal.WeekOfMonth; - cal.MinimalDaysInFirstWeek = newMinimum; - var val1 = cal.WeekOfMonth; - Assert.AreEqual(2, val0); - Assert.AreEqual(1, val1); + cal.MinimalDaysInFirstWeek = minimumDaysInFirstWeek; + return cal.WeekOfMonth; } } - [Test] - public void EraTest() + [TestCase(2000, ExpectedResult = 1)] + [TestCase(-1, ExpectedResult = 0)] + public int EraTest(int year) { using (var cal = new GregorianCalendar(new TimeZone("UTC"))) { - var era1 = cal.Era; - cal.Year = -1; - var era0 = cal.Era; - - Assert.AreEqual(1, era1); - Assert.AreEqual(0, era0); + cal.Year = year; + return cal.Era; } } @@ -425,56 +405,58 @@ public void ZoneOffsetTest() } } - [Test] - public void DstOffsetTest() + [TestCase(Calendar.UCalendarMonths.July, ExpectedResult = 3600000 /* 60min * 60s * 1000ms */)] + [TestCase(Calendar.UCalendarMonths.January, ExpectedResult = 0)] + public int DstOffsetTest(Calendar.UCalendarMonths month) { - var expected0 = 60 * 60 * 1000; - var expected1 = 0; - var zone = new TimeZone("Europe/Paris"); using (var cal = new GregorianCalendar(zone)) { - cal.Month = Calendar.UCalendarMonths.July; + cal.Month = month; cal.DayOfMonth = 20; - var offset0 = cal.DstOffset; - cal.Month = Calendar.UCalendarMonths.January; - var offset1 = cal.DstOffset; + return cal.DstOffset; + } + } - Assert.AreEqual(expected0, offset0); - Assert.AreEqual(expected1, offset1); + [TestCase(3, ExpectedResult = Calendar.UCalendarAMPMs.Am)] + [TestCase(14, ExpectedResult = Calendar.UCalendarAMPMs.Pm)] + public Calendar.UCalendarAMPMs AmPmTest(int hourOfDay) + { + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.HourOfDay = hourOfDay; + return cal.AmPm; } } [Test] - public void AmPmTest() + [Platform(Include = "win")] + public void SetTimeZoneTestWin() { + var timezones = TimeZoneInfo.GetSystemTimeZones(); + var timezone = timezones.First(tzi => tzi.Id == "Romance Standard Time"); + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) { - cal.HourOfDay = 3; - var val0 = cal.AmPm; - cal.HourOfDay = 14; - var val1 = cal.AmPm; + cal.SetTimeZone(timezone); - Assert.AreEqual(Calendar.UCalendarAMPMs.Am, val0); - Assert.AreEqual(Calendar.UCalendarAMPMs.Pm, val1); + var tz = cal.GetTimeZone(); + + Assert.AreEqual("Europe/Paris", tz.Id); } } [Test] - public void SetTimeZone2Test() + [Platform(Exclude = "win")] + public void SetTimeZoneTestLinux() { var tzdbId = "Europe/Paris"; - var winId = "Romance Standard Time"; - + var timezones = TimeZoneInfo.GetSystemTimeZones(); - var timezone = timezones.FirstOrDefault(tzi => tzi.Id == tzdbId); - if(timezone==null) - { - timezone = timezones.First(tzi => tzi.Id == winId); - } + var timezone = timezones.First(tzi => tzi.Id == tzdbId); using (var cal = new GregorianCalendar(new TimeZone("UTC"))) { @@ -487,10 +469,24 @@ public void SetTimeZone2Test() } [Test] - public void GetTimeZoneInfoTest() + [Platform(Include = "win")] + public void GetTilmeZoneInfoTestWin() + { + var timezone = new TimeZone("Europe/Zagreb"); + + using (var cal = new GregorianCalendar(timezone)) + { + var result = cal.GetTimeZoneInfo(); + + Assert.IsTrue(result.Id == "Central European Standard Time"); + } + } + + [Test] + [Platform(Exclude = "win")] + public void GetTimeZoneInfoTestLinux() { var tzdbId = "Europe/Zagreb"; - var winId = "Central European Standard Time"; var timezone = new TimeZone(tzdbId); @@ -498,10 +494,8 @@ public void GetTimeZoneInfoTest() { var result = cal.GetTimeZoneInfo(); - Assert.IsTrue(result.Id == winId || result.Id == tzdbId); + Assert.IsTrue(result.Id == tzdbId); } } - - } } From 691f58e613c544dba188833d7ba56fa701bad9ce Mon Sep 17 00:00:00 2001 From: Jakub Troc Date: Wed, 26 Feb 2020 13:29:34 +0100 Subject: [PATCH 6/6] Fix calendar test issues --- source/icu.net.tests/CalendarTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/icu.net.tests/CalendarTests.cs b/source/icu.net.tests/CalendarTests.cs index d17f52a6..86875267 100644 --- a/source/icu.net.tests/CalendarTests.cs +++ b/source/icu.net.tests/CalendarTests.cs @@ -470,7 +470,7 @@ public void SetTimeZoneTestLinux() [Test] [Platform(Include = "win")] - public void GetTilmeZoneInfoTestWin() + public void GetTimeZoneInfoTestWin() { var timezone = new TimeZone("Europe/Zagreb"); @@ -478,7 +478,7 @@ public void GetTilmeZoneInfoTestWin() { var result = cal.GetTimeZoneInfo(); - Assert.IsTrue(result.Id == "Central European Standard Time"); + Assert.AreEqual("Central European Standard Time",result.Id); } } @@ -494,7 +494,7 @@ public void GetTimeZoneInfoTestLinux() { var result = cal.GetTimeZoneInfo(); - Assert.IsTrue(result.Id == tzdbId); + Assert.AreEqual(tzdbId, result.Id); } } }