using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Text;
+using System.Globalization;
#if LIBC || MONODROID
using System.IO;
return BuildFromStream ("Local", stream);
}
#else
+#if !NET_2_1
if (IsWindows && LocalZoneKey != null) {
string name = (string)LocalZoneKey.GetValue ("TimeZoneKeyName");
+ if (name == null)
+ name = (string)LocalZoneKey.GetValue ("StandardName"); // windows xp
name = TrimSpecial (name);
if (name != null)
return TimeZoneInfo.FindSystemTimeZoneById (name);
}
+#endif
var tz = Environment.GetEnvironmentVariable ("TZ");
if (tz != null) {
/// </summary>
private static string TrimSpecial (string str)
{
+ if (str == null)
+ return str;
var Istart = 0;
while (Istart < str.Length && !char.IsLetterOrDigit(str[Istart])) Istart++;
var Iend = str.Length - 1;
{
if (destinationTimeZone == null)
throw new ArgumentNullException("destinationTimeZone");
-
+
var utcDateTime = dateTimeOffset.UtcDateTime;
- AdjustmentRule rule = destinationTimeZone.GetApplicableRule (utcDateTime);
-
- if (rule != null && destinationTimeZone.IsDaylightSavingTime(utcDateTime)) {
- var offset = destinationTimeZone.BaseUtcOffset + rule.DaylightDelta;
- return new DateTimeOffset(DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified) + offset, offset);
- }
- else {
- return new DateTimeOffset(DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified) + destinationTimeZone.BaseUtcOffset, destinationTimeZone.BaseUtcOffset);
- }
+
+ bool isDst;
+ var utcOffset = destinationTimeZone.GetUtcOffset(utcDateTime, out isDst);
+
+ return new DateTimeOffset(DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified) + utcOffset, utcOffset);
}
public static DateTime ConvertTimeBySystemTimeZoneId (DateTime dateTime, string destinationTimeZoneId)
if (this == TimeZoneInfo.Utc)
return DateTime.SpecifyKind (dateTime, DateTimeKind.Utc);
-
- //FIXME: do not rely on DateTime implementation !
- if (this == TimeZoneInfo.Local)
- {
- return dateTime.ToLocalTime ();
- }
+ var utcOffset = GetUtcOffset (dateTime);
- AdjustmentRule rule = GetApplicableRule (dateTime);
- if (rule != null && IsDaylightSavingTime (DateTime.SpecifyKind (dateTime, DateTimeKind.Utc)))
- return DateTime.SpecifyKind (dateTime + BaseUtcOffset + rule.DaylightDelta , DateTimeKind.Unspecified);
- else
- return DateTime.SpecifyKind (dateTime + BaseUtcOffset, DateTimeKind.Unspecified);
+ var kind = (this == TimeZoneInfo.Local)? DateTimeKind.Local : DateTimeKind.Unspecified;
+
+ return DateTime.SpecifyKind (dateTime + utcOffset, kind);
}
public static DateTime ConvertTimeFromUtc (DateTime dateTime, TimeZoneInfo destinationTimeZone)
return ConvertTimeToUtc (dateTime, TimeZoneInfo.Local);
}
+ static internal DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfoOptions flags)
+ {
+ return ConvertTimeToUtc (dateTime, TimeZoneInfo.Local, flags);
+ }
+
public static DateTime ConvertTimeToUtc (DateTime dateTime, TimeZoneInfo sourceTimeZone)
{
- if (sourceTimeZone == null)
- throw new ArgumentNullException ("sourceTimeZone");
+ return ConvertTimeToUtc (dateTime, sourceTimeZone, TimeZoneInfoOptions.None);
+ }
- if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone != TimeZoneInfo.Utc)
- throw new ArgumentException ("Kind property of dateTime is Utc but the sourceTimeZone does not equal TimeZoneInfo.Utc");
+ static DateTime ConvertTimeToUtc (DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfoOptions flags)
+ {
+ if ((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) {
+ if (sourceTimeZone == null)
+ throw new ArgumentNullException ("sourceTimeZone");
- if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone != TimeZoneInfo.Local)
- throw new ArgumentException ("Kind property of dateTime is Local but the sourceTimeZone does not equal TimeZoneInfo.Local");
+ if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone != TimeZoneInfo.Utc)
+ throw new ArgumentException ("Kind property of dateTime is Utc but the sourceTimeZone does not equal TimeZoneInfo.Utc");
- if (sourceTimeZone.IsInvalidTime (dateTime))
- throw new ArgumentException ("dateTime parameter is an invalid time");
+ if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone != TimeZoneInfo.Local)
+ throw new ArgumentException ("Kind property of dateTime is Local but the sourceTimeZone does not equal TimeZoneInfo.Local");
+
+ if (sourceTimeZone.IsInvalidTime (dateTime))
+ throw new ArgumentException ("dateTime parameter is an invalid time");
+ }
if (dateTime.Kind == DateTimeKind.Utc)
return dateTime;
- if (sourceTimeZone.IsAmbiguousTime (dateTime) || !sourceTimeZone.IsDaylightSavingTime (dateTime))
- return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset, DateTimeKind.Utc);
- else {
- AdjustmentRule rule = sourceTimeZone.GetApplicableRule (dateTime);
- if (rule != null)
- return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset - rule.DaylightDelta, DateTimeKind.Utc);
- else
- return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset, DateTimeKind.Utc);
- }
+ bool isDst;
+ var utcOffset = sourceTimeZone.GetUtcOffset (dateTime, out isDst);
+
+ return DateTime.SpecifyKind (dateTime - utcOffset, DateTimeKind.Utc);
+ }
+
+ static internal TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out Boolean isAmbiguousLocalDst)
+ {
+ bool isDaylightSavings;
+ return GetUtcOffsetFromUtc(time, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst);
}
public static TimeZoneInfo CreateCustomTimeZone (string id, TimeSpan baseUtcOffset, string displayName, string standardDisplayName)
#if !NET_2_1
if (TimeZoneKey != null)
{
+ if (id == "Coordinated Universal Time")
+ id = "UTC"; //windows xp exception for "StandardName" property
RegistryKey key = TimeZoneKey.OpenSubKey (id, false);
if (key == null)
throw new TimeZoneNotFoundException ();
tz = TimeZoneInfo.Local;
bool isTzDst;
- var tzOffset = GetUtcOffset (dateTime, tz, out isTzDst);
+ var tzOffset = GetUtcOffsetHelper (dateTime, tz, out isTzDst);
if (tz == this) {
isDST = isTzDst;
var utcDateTime = new DateTime (utcTicks, DateTimeKind.Utc);
- return GetUtcOffset (utcDateTime, this, out isDST);
+ return GetUtcOffsetHelper (utcDateTime, this, out isDST);
}
- private static TimeSpan GetUtcOffset (DateTime dateTime, TimeZoneInfo tz, out bool isDST)
+ // This is an helper method used by the method above, do not use this on its own.
+ private static TimeSpan GetUtcOffsetHelper (DateTime dateTime, TimeZoneInfo tz, out bool isDST)
{
if (dateTime.Kind == DateTimeKind.Local && tz != TimeZoneInfo.Local)
throw new Exception ();
return isDst;
}
+ internal bool IsDaylightSavingTime (DateTime dateTime, TimeZoneInfoOptions flags)
+ {
+ return IsDaylightSavingTime (dateTime);
+ }
+
public bool IsDaylightSavingTime (DateTimeOffset dateTimeOffset)
{
throw new NotImplementedException ();
if (dateTime >= tpoint && dateTime < tpoint + rule.DaylightDelta)
return true;
}
-
+
return false;
}
private AdjustmentRule GetApplicableRule (DateTime dateTime)
{
- //Transitions are always in standard time
+ //Applicable rules are in standard time
DateTime date = dateTime;
if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Local)
if (transitions == null)
return false;
- //Transitions are always in standard time
+ //Transitions are in UTC
DateTime date = dateTime;
- if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Local)
- date = date.ToUniversalTime () + BaseUtcOffset;
+ if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Local) {
+ var ticks = date.ToUniversalTime ().Ticks + BaseUtcOffset.Ticks;
+ if (ticks < DateTime.MinValue.Ticks || ticks > DateTime.MaxValue.Ticks)
+ return false;
- if (dateTime.Kind == DateTimeKind.Utc && this != TimeZoneInfo.Utc)
- date = date + BaseUtcOffset;
+ date = new DateTime (ticks, DateTimeKind.Utc);
+ }
+
+ if (dateTime.Kind != DateTimeKind.Utc) {
+ var ticks = date.Ticks - BaseUtcOffset.Ticks;
+ if (ticks < DateTime.MinValue.Ticks || ticks > DateTime.MaxValue.Ticks)
+ return false;
+
+ date = new DateTime (ticks, DateTimeKind.Utc);
+ }
for (var i = transitions.Count - 1; i >= 0; i--) {
var pair = transitions [i];
DateTime date_time = new DateTime (1970, 1, 1);
return date_time.AddSeconds (unix_time);
}
+
+#region reference sources
+ // Shortcut for TimeZoneInfo.Local.GetUtcOffset
+ internal static TimeSpan GetLocalUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags)
+ {
+ bool dst;
+ return Local.GetUtcOffset (dateTime, out dst);
+ }
+
+ internal TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags)
+ {
+ bool dst;
+ return GetUtcOffset (dateTime, out dst);
+ }
+
+ static internal TimeSpan GetUtcOffsetFromUtc (DateTime time, TimeZoneInfo zone, out Boolean isDaylightSavings, out Boolean isAmbiguousLocalDst)
+ {
+ isDaylightSavings = false;
+ isAmbiguousLocalDst = false;
+ TimeSpan baseOffset = zone.BaseUtcOffset;
+
+ if (zone.IsAmbiguousTime (time)) {
+ isAmbiguousLocalDst = true;
+ return baseOffset;
+ }
+
+ return zone.GetUtcOffset (time, out isDaylightSavings);
+ }
+#endregion
}
struct TimeType {