diff --git a/source/icu.net.tests/CalendarTests.cs b/source/icu.net.tests/CalendarTests.cs new file mode 100644 index 00000000..86875267 --- /dev/null +++ b/source/icu.net.tests/CalendarTests.cs @@ -0,0 +1,501 @@ +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"); + using (var cal = new GregorianCalendar(timezone)) + { + var displayName = cal.GetTimeZoneDisplayName(Calendar.UCalendarDisplayNameType.Standard); + + Assert.AreEqual("Alaska Standard Time", displayName); + } + } + + [Test] + public void ClearTest() + { + using (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() + { + using (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() + { + 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() + { + using (var cal = new GregorianCalendar()) + { + var startMonth = cal.Month; + + cal.Roll(Calendar.UCalendarDateFields.DayOfMonth, 100); + + Assert.AreEqual(startMonth, cal.Month); + } + } + + [Test] + public void SetTest() + { + using (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 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() + { + using (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() + { + using (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() + { + 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() + { + using (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() + { + 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); + + 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() + { + 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"); + + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.SetTimeZone(expected); + var result = cal.GetTimeZone(); + + Assert.AreEqual(expected.Id, result.Id); + } + } + + [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"))) + { + cal.FirstDayOfWeek = firstDayOfWeek; + return cal.FirstDayOfWeek; + } + } + + [TestCase(Calendar.UCalendarDaysOfWeek.Sunday, ExpectedResult = 2)] + [TestCase(Calendar.UCalendarDaysOfWeek.Thursday, ExpectedResult = 1)] + [Test] + public int WeekOfYearTest(Calendar.UCalendarDaysOfWeek firstDayOfWeek) + { + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.Clear(); + cal.DayOfMonth = 4; + + cal.FirstDayOfWeek = firstDayOfWeek; + return cal.WeekOfYear; + } + } + + [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; + + cal.MinimalDaysInFirstWeek = minimumDaysInFirstWeek; + return cal.WeekOfYear; + } + } + + [Test] + public void SkippedWallTimeTest() + { + 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() + { + 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() + { + 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()); + } + } + + [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; + + cal.MinimalDaysInFirstWeek = minimumDaysInFirstWeek; + return cal.WeekOfMonth; + } + } + + [TestCase(2000, ExpectedResult = 1)] + [TestCase(-1, ExpectedResult = 0)] + public int EraTest(int year) + { + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.Year = year; + return cal.Era; + } + } + + [Test] + public void ZoneOffsetTest() + { + var expected = 60 * 60 * 1000; + var zone = new TimeZone("Europe/Paris"); + + using (var cal = new GregorianCalendar(zone)) + { + var offset = cal.ZoneOffset; + + Assert.AreEqual(expected, offset); + } + } + + [TestCase(Calendar.UCalendarMonths.July, ExpectedResult = 3600000 /* 60min * 60s * 1000ms */)] + [TestCase(Calendar.UCalendarMonths.January, ExpectedResult = 0)] + public int DstOffsetTest(Calendar.UCalendarMonths month) + { + var zone = new TimeZone("Europe/Paris"); + + using (var cal = new GregorianCalendar(zone)) + { + cal.Month = month; + cal.DayOfMonth = 20; + + return cal.DstOffset; + } + } + + [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] + [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.SetTimeZone(timezone); + + var tz = cal.GetTimeZone(); + + Assert.AreEqual("Europe/Paris", tz.Id); + } + } + + [Test] + [Platform(Exclude = "win")] + public void SetTimeZoneTestLinux() + { + var tzdbId = "Europe/Paris"; + + var timezones = TimeZoneInfo.GetSystemTimeZones(); + + var timezone = timezones.First(tzi => tzi.Id == tzdbId); + + using (var cal = new GregorianCalendar(new TimeZone("UTC"))) + { + cal.SetTimeZone(timezone); + + var tz = cal.GetTimeZone(); + + Assert.AreEqual(tzdbId, tz.Id); + } + } + + [Test] + [Platform(Include = "win")] + public void GetTimeZoneInfoTestWin() + { + var timezone = new TimeZone("Europe/Zagreb"); + + using (var cal = new GregorianCalendar(timezone)) + { + var result = cal.GetTimeZoneInfo(); + + Assert.AreEqual("Central European Standard Time",result.Id); + } + } + + [Test] + [Platform(Exclude = "win")] + public void GetTimeZoneInfoTestLinux() + { + var tzdbId = "Europe/Zagreb"; + + var timezone = new TimeZone(tzdbId); + + using (var cal = new GregorianCalendar(timezone)) + { + var result = cal.GetTimeZoneInfo(); + + Assert.AreEqual(tzdbId, result.Id); + } + } + } +} diff --git a/source/icu.net/Calendar/Calendar.cs b/source/icu.net/Calendar/Calendar.cs new file mode 100644 index 00000000..3a664b9c --- /dev/null +++ b/source/icu.net/Calendar/Calendar.cs @@ -0,0 +1,845 @@ +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 _isDisposed; // 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. + /// Time will be set to matching time in calendar's timezone. + /// + /// The given date + public void SetTime(DateTime dateTime) + { + 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; + + // Offset to calendars local timezone + Add(UCalendarDateFields.Millisecond, ZoneOffset+DstOffset); + } + + /// + /// 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; + + if(!TimeZone.GetTimeZones().Any(tz=>tz.Id == id)) + id = TimeZone.GetIdForWindowsId(id, _locale?.Country); + + SetTimeZone(id); + } + + /// + /// Returns time zone set for this calendar. + /// + /// Time zone set for this calendar. + public TimeZone GetTimeZone() + { + string result = NativeMethods.GetUnicodeString((ptr, length) => + { + length = NativeMethods.ucal_getTimeZoneId(_calendarHandle, ptr, length, out ErrorCode status); + return new Tuple(status, length); + }, 255); + 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) + { + return NativeMethods.GetUnicodeString((ptr, length) => + { + length = NativeMethods.ucal_getTimeZoneDisplayName(_calendarHandle, type, _locale.Name, ptr, length, out ErrorCode status); + return new Tuple(status, length); + }, 255); + } + + #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); + 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); + } + 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.MinimalDaysInFirstWeek); + return result; + } + set + { + NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.MinimalDaysInFirstWeek, 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); + + return result; + } + set + { + NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.RepeatedWallTime, (int)value); + } + } + + /// + /// + /// + public UCalendarWallTimeOption SkippedWallTimeOption + { + get + { + var result = (UCalendarWallTimeOption)NativeMethods.ucal_getAttribute(_calendarHandle, UCalendarAttribute.SkippedWallTime); + + return result; + } + set + { + NativeMethods.ucal_setAttribute(_calendarHandle, UCalendarAttribute.SkippedWallTime, (int)value); + } + } + + /// + /// Gets or sets era. + /// + public int Era + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Era, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Era, value); + } + } + + /// + /// Gets or sets year. + /// + public int Year + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Year, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Year, value); + } + } + + /// + /// Gets or sets motnth. + /// + public UCalendarMonths Month + { + get + { + var result = (UCalendarMonths)NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Month, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Month, (int)value); + } + } + + /// + /// Gets or sets week of year. + /// + public int WeekOfYear + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.WeekOfYear, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.WeekOfYear, value); + } + } + + /// + /// Gets or sets week of month. + /// + public int WeekOfMonth + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.WeekOfMonth, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.WeekOfMonth, value); + } + } + + /// + /// Gets or sets day of week. + /// + public int DayOfWeek + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfWeek, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.DayOfWeek, value); + } + } + + /// + /// Gets or sets day of month. + /// + public int DayOfMonth + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfMonth, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + 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 + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfWeekInMonth, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.DayOfWeekInMonth, value); + } + } + + /// + /// Gets or sets day of year. + /// + public int DayOfYear + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DayOfYear, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.DayOfYear, value); + } + } + + /// + /// Gets or seths whether the hour is before or after noon. + /// + public UCalendarAMPMs AmPm + { + get + { + var result = (UCalendarAMPMs)NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.AmPm, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.AmPm, (int)value); + } + } + + /// + /// Gets or sets hour in 12 hour based format. + /// + public int Hour + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Hour, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Hour, value); + } + } + + /// + /// Gets or sets hour in 24 hour based format. + /// + public int HourOfDay + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.HourOfDay, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.HourOfDay, value); + } + } + + /// + /// Gets or sets minute. + /// + public int Minute + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Minute, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Minute, value); + } + } + + /// + /// Gets or sets second. + /// + public int Second + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Second, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Second, value); + } + } + + /// + /// Gets or sets millisecond. + /// + public int Millisecond + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.Millisecond, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.Millisecond, value); + } + } + + /// + /// Gets or sets time zone ofset. + /// + public int ZoneOffset + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.ZoneOffset, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + set + { + NativeMethods.ucal_set(_calendarHandle, UCalendarDateFields.ZoneOffset, value); + } + } + + /// + /// Gets or sets daylight savings time offset. + /// + public int DstOffset + { + get + { + var result = NativeMethods.ucal_get(_calendarHandle, UCalendarDateFields.DstOffset, out ErrorCode errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + return result; + } + 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 (!_isDisposed) + { + if (disposing) + { + _calendarHandle.Dispose(); + } + + _isDisposed = 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..3bba54f9 --- /dev/null +++ b/source/icu.net/Calendar/GregorianCalendar.cs @@ -0,0 +1,53 @@ +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 errorCode); + ExceptionFromErrorCode.ThrowIfError(errorCode); + } + + private GregorianCalendar(SafeCalendarHandle handle) + { + _calendarHandle = handle; + } + + public override Calendar Clone() + { + 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() + { + 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 new file mode 100644 index 00000000..1bf037db --- /dev/null +++ b/source/icu.net/NativeMethods/NativeMethods_Calendar.cs @@ -0,0 +1,377 @@ +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); + + [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, + IntPtr result, + int resultLength, + out ErrorCode ec) + { + if (CalendarMethods.ucal_getTimeZoneId == null) + CalendarMethods.ucal_getTimeZoneId = GetMethod(IcuI18NLibHandle, "ucal_getTimeZoneID"); + + return CalendarMethods.ucal_getTimeZoneId(cal, result, resultLength, out ec); + } + + 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) + { + if (CalendarMethods.ucal_getAttribute == null) + CalendarMethods.ucal_getAttribute = GetMethod(IcuI18NLibHandle, "ucal_getAttribute"); + return CalendarMethods.ucal_getAttribute(cal, attribute); + } + + 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, + IntPtr result, + int resultLength, + out ErrorCode status) + { + if (CalendarMethods.ucal_getTimeZoneDisplayName == null) + CalendarMethods.ucal_getTimeZoneDisplayName = GetMethod(IcuI18NLibHandle, "ucal_getTimeZoneDisplayName"); + return CalendarMethods.ucal_getTimeZoneDisplayName(cal, type, locale, result, resultLength, out status); + } + + 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 + } +}