5 // Duncan Mak (duncan@ximian.com)
6 // Ajay Kumar Dwivedi (adwiv@yahoo.com)
7 // Martin Baulig (martin@gnome.org)
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System
.Collections
;
36 using System
.Globalization
;
37 using System
.Runtime
.CompilerServices
;
42 public abstract class TimeZone
45 private static TimeZone currentTimeZone
;
53 public static TimeZone CurrentTimeZone
{
55 if (currentTimeZone
== null)
56 currentTimeZone
= new CurrentTimeZone ();
58 return currentTimeZone
;
62 public abstract string DaylightName
{
66 public abstract string StandardName
{
71 public abstract DaylightTime
GetDaylightChanges (int year
);
73 public abstract TimeSpan
GetUtcOffset (DateTime time
);
75 public virtual bool IsDaylightSavingTime (DateTime time
)
77 return IsDaylightSavingTime (time
, GetDaylightChanges (time
.Year
));
80 public static bool IsDaylightSavingTime (DateTime time
, DaylightTime daylightTimes
)
82 if (daylightTimes
== null)
83 throw new ArgumentNullException ("daylightTimes");
85 // If Start == End, then DST is off
86 if (daylightTimes
.Start
.Ticks
== daylightTimes
.End
.Ticks
)
89 //We are in the northern hemisphere.
90 if (daylightTimes
.Start
.Ticks
< daylightTimes
.End
.Ticks
) {
91 if (daylightTimes
.Start
.Ticks
< time
.Ticks
&& daylightTimes
.End
.Ticks
> time
.Ticks
)
92 return true; // time lies between Start and End
95 else { // We are in the southern hemisphere.
96 if (time
.Year
== daylightTimes
.Start
.Year
&& time
.Year
== daylightTimes
.End
.Year
)
97 if (time
.Ticks
< daylightTimes
.End
.Ticks
|| time
.Ticks
> daylightTimes
.Start
.Ticks
)
98 return true; // time is less than End OR more than Start
104 public virtual DateTime
ToLocalTime (DateTime time
)
106 return time
+ GetUtcOffset (time
);
109 public virtual DateTime
ToUniversalTime (DateTime time
)
111 return time
- GetUtcOffset (time
);
115 internal class CurrentTimeZone
: TimeZone
118 private static string daylightName
;
119 private static string standardName
;
121 // A yearwise cache of DaylightTime.
122 private static Hashtable daylightCache
= new Hashtable (1);
124 // the offset when daylightsaving is not on.
125 private static TimeSpan utcOffsetWithOutDLS
;
127 // the offset when daylightsaving is on.
128 private static TimeSpan utcOffsetWithDLS
;
130 internal enum TimeZoneData
132 DaylightSavingStartIdx
,
133 DaylightSavingEndIdx
,
135 AdditionalDaylightOffsetIdx
138 internal enum TimeZoneNames
144 // Internal method to get timezone data.
145 // data[0]: start of daylight saving time (in DateTime ticks).
146 // data[1]: end of daylight saving time (in DateTime ticks).
147 // data[2]: utcoffset (in TimeSpan ticks).
148 // data[3]: additional offset when daylight saving (in TimeSpan ticks).
149 // name[0]: name of this timezone when not daylight saving.
150 // name[1]: name of this timezone when daylight saving.
151 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
152 private static extern bool GetTimeZoneData (int year
, out Int64
[] data
, out string[] names
);
155 internal CurrentTimeZone ()
161 DateTime now
= new DateTime(DateTime
.GetNow ());
162 if (!GetTimeZoneData (now
.Year
, out data
, out names
))
163 throw new NotSupportedException (Locale
.GetText ("Can't get timezone name."));
165 standardName
= Locale
.GetText (names
[(int)TimeZoneNames
.StandardNameIdx
]);
166 daylightName
= Locale
.GetText (names
[(int)TimeZoneNames
.DaylightNameIdx
]);
168 utcOffsetWithOutDLS
= new TimeSpan (data
[(int)TimeZoneData
.UtcOffsetIdx
]);
169 utcOffsetWithDLS
= new TimeSpan (data
[(int)TimeZoneData
.UtcOffsetIdx
]
170 + data
[(int)TimeZoneData
.AdditionalDaylightOffsetIdx
]);
174 public override string DaylightName
{
175 get { return daylightName; }
178 public override string StandardName
{
179 get { return standardName; }
184 public override DaylightTime
GetDaylightChanges (int year
)
186 if (year
< 1 || year
> 9999)
187 throw new ArgumentOutOfRangeException ("year", year
+
188 Locale
.GetText (" is not in a range between 1 and 9999."));
190 if (daylightCache
[year
] == null) {
192 if (daylightCache
[year
] == null) {
196 if (!GetTimeZoneData (year
, out data
, out names
))
197 throw new ArgumentException (Locale
.GetText ("Can't get timezone data for " + year
));
199 DaylightTime dlt
= new DaylightTime (new DateTime (data
[(int)TimeZoneData
.DaylightSavingStartIdx
]),
200 new DateTime (data
[(int)TimeZoneData
.DaylightSavingEndIdx
]),
201 new TimeSpan (data
[(int)TimeZoneData
.AdditionalDaylightOffsetIdx
]));
202 daylightCache
.Add (year
, dlt
);
207 return (DaylightTime
) daylightCache
[year
];
210 public override TimeSpan
GetUtcOffset (DateTime time
)
212 if (IsDaylightSavingTime (time
))
213 return utcOffsetWithDLS
;
215 return utcOffsetWithOutDLS
;