This question already has answers here:
How to make ASP.Net MVC model binder treat incoming date as UTC?
(7 answers)
Closed 5 years ago.
I'm having trouble with DateTimes in my ASP.NET C# Web Api 2 project. I need to pass through an ISO 8601 date in my query string as follows:
api/resource?at=2016-02-14T23:30:58Z
My controller method is as follows
[HttpGet("/resource")]
public IActionResult GetResource([FromQuery]DateTime? at = null)
{
if (!at.HasValue)
{
at = DateTime.UtcNow;
}
else
{
at = DateTime.SpecifyKind(at.Value, DateTimeKind.Utc);
}
// ...
}
Notice the little hack - the date is coming in with a DateTimeKind of Local, despite being specified with the 'Z' signifying UTC. Dates should always be passed in UTC although I would ideally not like this to be a constraint. I am using NodaTime internally and only expose DateTime in the query and response models for legacy reasons.
Why are my dates parsed to a DateTimeKind of local?
How can I read my UTC dates from query strings using ASP.NET web api 2?
If you use DateTimeOffset instead of DateTime, the time-zone offset is preserved. You could then either use it directly, or convert it to a DateTime via the UtcDateTime property.
DateTimeOffset dto = DateTimeOffset.Parse("2016-02-14T23:30:58Z");
DateTime dt = dto.UtcDateTime;
[HttpGet("/resource")]
public IActionResult GetResource([FromQuery]DateTimeOffset? at = null)
{
if (!at.HasValue)
{
at = DateTimeOffset.UtcNow;
}
// ...
}
Related
I find it hard to understand how UTC works.
I have to do the following but I'm still confused if I'd get the right result.
Objectives:
Ensure all saved dates in Database are in UTC format
Update DefaultTimezone is in Manila time
Ensure all returned dates are in Manila Time
So the code is:
public ConvertDate(DateTime? dateTime)
{
if (dateTime != null)
{
Value = (DateTime)dateTime;
TimeZone = GetFromConfig.DefaultTimeZone();
}
}
public ConvertDate(DateTime? dateTime, int GMTTimeZone)
{
if (dateTime != null)
{
Value = (DateTime)dateTime;
TimeZone = GMTTimeZone;
}
}
public int TimeZone
{
get { return m_TimeZone; }
set { m_TimeZone = value; }
}
DateTime m_Value;
public DateTime Value
{
get { return m_Value; }
set
{
m_Value = value;
DateTime converted = m_Value.ToUniversalTime().ToLocalTime();
}
}
Sample usage:
DateTime SampleInputFromUser = new DateTime(2012, 1, 22);
ConvertDate newConversion = new ConvertDate(SampleInputFromUser, 21);
DateTime answer = newConversion.Value;
Now I get confused for 'TimeZone'. I don't know how to use it to get the objectives.
Hope you understand my question and have the idea to get the objectives done.
Edit
According to #raveturned answer, I get this following code:
***Added in ConvertDate method
TimeZoneInfo timeInfo = TimeZoneInfo.FindSystemTimeZoneById(GetFromConfig.ManilaTimeZoneKey());
ManilaTime = TimeZoneInfo.ConvertTime(dateTime.Value, TimeZoneInfo.Local, timeInfo).ToUniversalTime();
**New Property
DateTime _ManilaTime;
public DateTime ManilaTime
{
get { return _ManilaTime; }
set { _ManilaTime = value; }
}
The .NET framework already has classes and methods available to convert DateTimes between different time zones. Have a look at the ConvertTime methods of the TimeZoneInfo class.
Edit: When you get the time to put into the database, assuming it was created with correct time zone information you can easily convert to UTC:
DateTime utcTime = inputDateTime.ToUniversalTime();
Get timeInfo as done in the question edit:
TimeZoneInfo timeInfo = TimeZoneInfo.FindSystemTimeZoneById(GetFromConfig.ManilaTimeZoneKey());
When you send the database time to user, convert it to the correct timezone using timeInfo.
DateTime userTime = TimeZoneInfo.ConvertTimeFromUtc(dbDateTime, timeInfo);
Personally I'd try and keep this logic separate from the propery get/set methods.
var date = System.TimeZoneInfo.ConvertTimeFromUtc(
DateTime.UtcNow,
TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
TimeZoneInfo infotime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time (Mexico)");
DateTime thisDate = TimeZoneInfo.ConvertTimeFromUtc(datetimeFromBD, infotime);
To help others:
static void ChangeTimezone()
{
// Timezone string here:
foreach (TimeZoneInfo z in TimeZoneInfo.GetSystemTimeZones())
Console.WriteLine(z.Id);
// Use one of those timezone strings
DateTime localDt = DateTime.Today;
DateTime utcTime = localDt.ToUniversalTime();
TimeZoneInfo timeInfo = TimeZoneInfo.FindSystemTimeZoneById("US Eastern Standard Time");
DateTime estDt = TimeZoneInfo.ConvertTimeFromUtc(utcTime, timeInfo);
return;
}
For anyone facing problem in getting TimeZoneInfo in cross-platform (different time zone ids between Windows and Linux), .NET 6 addresses this issue:
Starting with this release, the TimeZoneInfo.FindSystemTimeZoneById method will automatically convert its input to the opposite format if the requested time zone is not found on the system. That means that you can now use either IANA or Windows time zone IDs on any operating system that has time zone data installed*. It uses the same CLDR mappings, but gets them through .NET’s ICU globalization support, so you don’t have to use a separate library.
A brief example:
// Both of these will now work on any supported OS where ICU and time zone data are available.
TimeZoneInfo tzi1 = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
TimeZoneInfo tzi2 = TimeZoneInfo.FindSystemTimeZoneById("Australia/Sydney");
Find more info here
And as mentioned in other answers: to get DateTime in the desired timezone from UTC, use TimeZoneInfo.ConvertTimeFromUtc(DateTime, TimeZoneInfo) Method
I wish to return a Json Result containing the datetime queried from database. The testing on my local machine is without any problem, however, after publishing to production server, all datetime show 3 hours ahead. I assume it is due to the server located in another timezone area.
Need help to solve this issue.
Data in Database (MS SQL):
StartDt: 2019-07-02 04:00:00.000
Controller.cs:
[HttpGet]
public ActionResult GetAll()
{
CalendarModel calendarModel = new CalendarModel();
var calendarEvents = from cal in db.Calendar
orderby cal.created descending
select cal;
return Json(calendarEvents, JsonRequestBehavior.AllowGet);
}
Json Result Fetched from my compuer:
[
{
//some data
"startDt": "/Date(1562054400000)/",
//some data
},
The above datetime is parsed as "2019-07-02T04:00:00.000-04:00", which is correct.
Json Result Fetched from production server (queried from same database):
[
{
//some data
"startDt": "/Date(1562065200000)/",
//some data
},
This datetime is "2019-07-02T07:00:00.000-04:00", which is wrong.
--------Update my solution-------
Thank #TommasoBertoni's answer inspired me that the key reason for this issue is due to the Unspecified DateTime Kind by default but turns to be local while Json serializing. So just need to set the DateTime Kind to UTC can solve that, but be aware that parsing the DateTime in front end also need to take it as UTC otherwise it will be considered as local by default.
Controller.cs:
[HttpGet]
public ActionResult GetAll()
{
CalendarModel calendarModel = new CalendarModel();
var calendarEvents = from cal in db.Calendar
orderby cal.created descending
select cal;
//Add this
foreach (var item in calendarEvents)
{
item.startDt = DateTime.SpecifyKind(item.startDt, DateTimeKind.Utc);
}
return Json(calendarEvents, JsonRequestBehavior.AllowGet);
}
.js
(using moment.js library)
//parse it as utc
moment.utc(startDt).format("YYYY-MM-DDTHH:mm:ss")
The problem is that ASP.NET uses a custom Microsoft JSON date format, that encodes DateTime values as /Date(ticks)/, where ticks represents milliseconds since epoch (UTC).
So November 29, 1989, 4:55:30 AM, in UTC is encoded as /Date(628318530718)/ (see here for more).
Example:
Microsoft JSON date format: /Date(1563464520158)/
ISO 8601 format: 2019-07-18T15:42:02.4592008Z
If a DateTime has an Unspecified kind, it will be assumed as Local and the value will be conveted to UTC in order to get the ticks since epoch.
This json format is still used in MVC, but not in Web API: this means that when you are in a Controller and serialize the result with Json(...) you'll get the non-ISO format, but if you're in an ApiController the default serializer is Json.NET, which supports the ISO 8601 format and won't convert the DateTime value.
So, to fix this behavior either you switch to Web APIs, or if you want to keep using the MVC controller, you can see the answers to these questions:
Setting the default JSON serializer in ASP.NET MVC
Using JSON.NET as the default JSON serializer in ASP.NET MVC 3
How to use Json.NET for JSON modelbinding in an MVC5 project
...or you could force the DateTime Kind to be Utc right before the json serialization, but I wouldn't recommend that.
class TestRepo
{
public IEnumerable<DateTime> GetDates()
{
var now = DateTime.Now;
// Use DateTime instances with different Kind
// showing that it doesn't impact the serialization format.
var utc = DateTime.SpecifyKind(new DateTime(now.Ticks), DateTimeKind.Utc);
var local = DateTime.SpecifyKind(new DateTime(now.Ticks), DateTimeKind.Local);
var unspecified = DateTime.SpecifyKind(new DateTime(now.Ticks), DateTimeKind.Unspecified);
return new DateTime[] { utc, local, unspecified };
}
}
// MVC controller
public class MVCValuesController : Controller
{
public ActionResult Index()
{
IEnumerable<DateTime> dates = new TestRepo().GetDates();
return Json(dates, JsonRequestBehavior.AllowGet);
}
}
// json result:
[
"/Date(1563465361835)/", // <-- Utc
"/Date(1563458161835)/", // <-- Local
"/Date(1563458161835)/" // <-- Unspecified
]
// Web API controller
public class ValuesController : ApiController
{
public IEnumerable<DateTime> Get()
{
IEnumerable<DateTime> dates = new TestRepo().GetDates();
return dates;
}
}
// json result:
[
"2019-07-18T15:56:03.6401158Z", // <-- Utc
"2019-07-18T15:56:03.6401158+02:00", // <-- Local
"2019-07-18T15:56:03.6401158" // <-- Unspecified
]
I have a WCF service returning opening and closing times.
The problem is that the time is always represented with UTC+2.
Here's an example of my WCF code:
[XmlElementAttribute(Form = Schema.XmlSchemaForm.Unqualified, DataType = "time", Order = 1)]
public System.DateTime OpeningTime
{
get
{
string timeString = "10:00:00";
return XmlConvert.ToDateTime(timeString, XmlDateTimeSerializationMode.RoundtripKind);
}
}
The result in the response is:
<OpeningTime>10:00:00.0000000+02:00</ClosingTime>
But I need it with UTC 0 like
<ClosingTime>10:00:00.0000000+00:00</ClosingTime>
I have no clue how I can specify the timezone. I also tried using ToLocalTime() but it is always UTC+2.
I need the time as DateTime so converting the DateTime to string is no option.
Hey I'm getting diffrent date after deserialization.
before the date is 30.03.2017, and after the date is 29.03.2017.
before
after
Json string (stam value):
[{"a_id":1,"auctionname":"computer","deadLine":"\/Date(1490821200000)\/"},{"a_id":2,"auctionname":"keyboard","deadLine":"\/Date(1490821200000)\/"},{"a_id":3,"auctionname":"mouse","deadLine":"\/Date(1490821200000)\/"}]
my code:
[Test]
public void GetAuctionsByJson_works()
{
Mock<IAuctionRespository> mockAuction = new Mock<IAuctionRespository>();
mockAuction.Setup(m => m.Auctions).Returns(new Auction[]
{
new Auction { a_id=1, auctionname="computer", deadLine=DateTime.Today},
new Auction { a_id=2, auctionname="keyboard", deadLine=DateTime.Today},
new Auction { a_id=3, auctionname="mouse", deadLine=DateTime.Today}
}.AsQueryable());
CustomerController controller = new CustomerController(mockAuction.Object);
var actual = controller.GetAuctionsByJson() as JsonResult;
JavaScriptSerializer serializer = new JavaScriptSerializer();
string stam = serializer.Serialize(actual.Data);
List<Auction> result = serializer.Deserialize<List<Auction>>(serializer.Serialize(actual.Data));
//List<Auction> result = ser.ReadObject(actual);// as List<Auction>; //null --> decirialized
}
There are multiple issues.
First, the format \/Date(1490821200000)\/ isn't used anymore. It was used in the early 2000s when there was no defacto standard to represen time in AJAX calls. The number is an escaped number of ticks in UTC. The defacto standard is ISO8601, 2017-03-30T00:00:00Z.
Second JavascriptSerializer isn't used anymore. It's been replaced by Json.NET even in ASP.NET Web API. I'm not sure if it understands ISO8601 or not. It isn't used anyway, except in legacy code.
Finally, DateTime.Today returns the local time. DateTime.Today in a +3 timezone is 30/3/2017 12:00:00 am but 29/3/2017 09:00:00 pmin UTC. Its .Kind property is Local. Even Json.NET would serialize this as 2017-03-30T00:00:00+03:00
To get the current date in UTC, one should use DateTime.UtcNow.Date. This has a Kind value of Utc. Json.NET will serialize this as 2017-03-30T00:00:00Z
Try changind all calls to
DateTime.Today
with
DateTime.UtcNow.Date
This question already has answers here:
Convert UTC/GMT time to local time
(12 answers)
Closed 9 years ago.
I need to convert a utc datetime to a local datetime.
it should look something like this:
private DateTime localdate (DateTime UTC_DateTime)
{
DateTime local = new DateTime();
local = UTC_DateTime ..... ???
return local;
}
Thanks in advance for your Help!
Do it like so:
private DateTime Localdate (DateTime utc_DateTime)
{
DateTime local = new DateTime();
local = utc_DateTime.ToLocalTime();
return local;
}
But the method itself is "a bit" redundant.
Just a recommendation: Try to respect the "Pascal-case convention" embraced by C# which states that method names are capitalized and that parameter names are not (amongst other things).
use method DateTime.ToLocalTime()