ASP.NET match users local date and time with the system time - asp.net

I have some trouble understanding how to match users current date and time with the server time.
Example: let's assume I have a website where users can register themselves. One profile option is that they can select their local time zone. For this there is a drop-down menu from where they can choose the correct time zone. So a user from China will select probably (UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi, another user from Los Angeles will select (UTC-07:00) Mountain Time (US & Canada) (i assume) and a guy from Paris will select (UTC+01:00) Brussels, Copenhagen, Madrid, Paris.
The web application is running on a server in USA with it's specific time zone ...
Now ... All these users will want to receive an email notification next Friday at 19:00 their local time zone!!!
Here I am lost ... definitely the next Friday at 19:00 is not in the same time for all these users ...
How can I map their profile time zone, so the service running on my site will send the email notification next Friday at 19:00 user's local time zone???
I am at this stage at the moment ... populating the drop down menu with all time zones so users can select their current time zone in their profile.
When the page load's than the dropdown is populated with the time zone:
protected void Page_Load(object sender, EventArgs e)
{
ddlUserTimeZone.DataSource = GetTimeZones();
ddlUserTimeZone.DataTextField = "Name";
ddlUserTimeZone.DataValueField = "ID";
ddlUserTimeZone.DataBind();
}
public Collection<TimeZoneItem> GetTimeZones()
{
Collection<TimeZoneItem> timeZones = new Collection<TimeZoneItem>();
foreach (var timeZoneInfo in TimeZoneInfo.GetSystemTimeZones())
{
timeZones.Add(new TimeZoneItem
{
TimeZoneName = timeZoneInfo.DisplayName,
TimeZoneID = timeZoneInfo.Id
});
}
return timeZones;
}
public struct TimeZoneItem
{
public string TimeZoneName { get; set; }
public string TimeZoneID { get; set; }
}
Now, can you guys help with the matching of the profile time zone with the current time so the email is sent in the correct time?
Thanks in advance!

Are you just setting up this service? If so, run your web servers and database servers on Universal Time Coordinated (UTC or Zulu) time, not a local time zone. Everything is far easier to manage if you do that. I learned this the hard way.
UTC used to be called Greenwich Mean Time; it is timezone +00:00. It doesn't change for daylight savings time like US and European local time does.
This time zone thing is a pain, and worth getting right. Some countries have half-hour time zones.
At any rate, once you know each user's preferred time zone, and the time she wants her notification, you can then convert the time from local to UTC and store it.
Try something like this to get the user's hour and minute into UTC. (Time zone conversions need a date, because they depend on daylight savings time rules. There's one more complication. On the day when a time zone switches from daylight to standard, or vice versa, the UTC time for a notification will change. Most people handle this by recomputing the UTC date and time of the next notification (tomorrow's notification) as they send each notification. Consider this code.
TimeZoneInfo userLocal = ;//user's time zone
int hour = ;//whatever the user wants
int minute = ;//whatever the user wants
DateTime tomorrow = DateTime.Now.AddDays(1);
int year = tomorrow.Year;
int month = tomorrow.Month;
int day = tomorrow.Day;
DateTime notificationTime = new DateTime(year,month,day,
hour,minute,0,
DateTimeKind.Unspecified);
DateTime tomorrowNotificationTime = TimeZoneInfo.ConvertTimeToUtc(
notificationTime,userLocal);
This should get you the UTC time you need to deliver this user's notification tomorrow, in the correct time zone for tomorrow's date.

DateTime should ideally be stored on the server in UTC format.
You have the following data on your server
Timezone info of the user.
The time at which the user needs the notification.
The current local time on your server.
// Convert current local server time to UTC.
var serverUtc = DateTime.UtcNow;
// Convert UTC time to users local time. This gives you the date and time as per the user.
var userTimeZone = TimeZoneInfo.GetSystemTimeZones()[0]; // just an example. Replace with actual value.
var userCurrentTime = TimeZoneInfo.ConvertTime(serverUtc, userTimeZone);
/*
add a day to userCurrentTime till its Friday. Add/subtract minutes till its 7:00PM.
*/
var expectedNotificationTimeUtc = TimeZoneInfo.ConvertTimeToUtc(userCurrentTime, userTimeZone);
/*
1. store the expectedNotificationTimeUtc as the time you want to send the email.
2. your service can check for users their expectedNotificationTimeUtc and
if the UtcNow is within an acceptable range of the that time, send the email.
*/

Related

Was there a change in timezone for ToLocalTime

Currently I'm using ToLocalTime to convert the UTC date received from my backend. Is there a way to setup my ASP.NET Core 3.0 web site to use a specific timezone when calling ToLocalTime (instead of depending on the host region) -- or should I implement my own method/extension to converting to the time I need?
Official documentation of DateTime.ToLocalTime states:
Note that the exact output depends on the current culture and the local time zone of the system on which it is run.
You can use the TimeZoneInfo static method ConvertTimeFromUtc to convert an instance of DateTime (Note: if it's Kind property is Local you'll get an exception!) from Utc to whatever local time you want (Another note: the Kind property of the result is either Utc or Unspecified - depending on the target TimeZoneInfo).
Code example (copied from documentation page):
DateTime timeUtc = DateTime.UtcNow;
try
{
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
Console.WriteLine("The date and time are {0} {1}.",
cstTime,
cstZone.IsDaylightSavingTime(cstTime) ?
cstZone.DaylightName : cstZone.StandardName);
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("The registry does not define the Central Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.");
}

Determine Time Offset given Olson TZID and local DateTime?

I need to determine Time Offset given Olson TZID of an event and a DateTime of an event.
I suppose I can do it with a help of Noda Time, but I'm new here and need help - an example of actual API call sequence to perform this task.
A few more details of what we're using and doing.
We're running ASP.NET + SQL Server based Web site. Users of our site enter and save events which are happening at various locations. For each event Lat/Long and DateTime with time offset (of that event) are among required fields.
There are various scenarios of data entry, sometimes Lat/Long is entered first, sometimes DateTime is. System allows to determine Lat/Long from an address or a map point. We want Time Offset to be consistent with Lat/Long in most of the cases because we normally expect DateTime being entered as local to that event.
We use SQL Server DateTimeOffset field to store data.
We don't want to depend on third-party web services to determine an offset, but prefer our system to do that.
I'm free to download and use any necessary tools or data. I already downloaded shapefiles from http://efele.net/maps/tz/ and used Shape2SQL http://goo.gl/u7AUy to convert them to SQL Server table with TZIDs and GEOMs.
I know how to get TZID from Lat/Long by querying that table.
What I need, again, is to determine Time Offset from TZID and DateTime.
Thank you for Jon Skeet and Matt Johnson for providing an answer on Noda Time Google Group http://goo.gl/I9unm0. Jon explained how to get Microsoft BCL DateTimeOffset value given Olson TZID and NodaTime LocalDateTime values. Matt pointed to an example of determining if DST is active given ZonedDateTime: What is the System.TimeZoneInfo.IsDaylightSavingTime equivalent in NodaTime?
I'm going to write a blog post summarizing my experience of getting Olson TZID from Lat/Long, parsing DateTime string into LocalDateTime and determining DateTimeOffset. I'll show there how GetTmzIdByLocation(latitude, longitude) and GetRoughDateTimeOffsetByLocation(latitude, longitude) methods work and why I needed both (first method doesn't work for locations on ocean). Once I write this post I'll add a comment here.
Note, that parsing DateTime string in a code below is not optimal yet; as Matt explained in a Google Group post (link above) it's better to use Noda Time tools than BCL. See a related question at http://goo.gl/ZRZ7XP
My current code:
public object GetDateTimeOffset(string latitude, string longitude, string dateTime)
{
var tzFound = false;
var isDST = false;
var tmpDateTime = new DateTimeOffset(DateTime.Now).DateTime;
if (!String.IsNullOrEmpty(dateTime))
{
try
{
// Note: Looks stupid? I need to throw away TimeZone Offset specified in dateTime string (if any).
// Funny thing is that calling DateTime.Parse(dateTime) would automatically modify DateTime for its value in a system timezone.
tmpDateTime = DateTimeOffset.Parse(dateTime).DateTime;
}
catch (Exception) { }
}
try
{
var tmzID = GetTmzIdByLocation(latitude, longitude);
DateTimeOffset result;
if (String.IsNullOrEmpty(tmzID) || tmzID.ToLower() == "uninhabited") // TimeZone is unknown, it's probably an ocean, so we would just return time offest based on Lat/Long.
{
var offset = GetRoughDateTimeOffsetByLocation(latitude, longitude);
result = new DateTimeOffset(tmpDateTime, TimeSpan.FromMinutes(offset * 60)); // This only works correctly if tmpDateTime.Kind = Unspecified, see http://goo.gl/at3Vba
} // A known TimeZone is found, we can adjust for DST using Noda Time calls below.
else
{
tzFound = true;
// This was provided by Jon Skeet
var localDateTime = LocalDateTime.FromDateTime(tmpDateTime); // See Noda Time docs at http://goo.gl/XseiSa
var dateTimeZone = DateTimeZoneProviders.Tzdb[tmzID];
var zonedDateTime = localDateTime.InZoneLeniently(dateTimeZone); // See Noda Time docs at http://goo.gl/AqE8Qo
result = zonedDateTime.ToDateTimeOffset(); // BCL DateTimeOffset
isDST = zonedDateTime.IsDaylightSavingsTime();
}
return new { result = result.ToString(IncidentDateFormat), tzFound, isDST };
}
catch (Exception ex)
{
IMAPLog.LogEvent(System.Reflection.MethodBase.GetCurrentMethod().Name, "", ex);
throw new CustomHttpException("Unable to get timezone offset.");
}
}
An extension method (provided by Matt Johnson) for determining if DST is active What is the System.TimeZoneInfo.IsDaylightSavingTime equivalent in NodaTime?
public static class NodaTimeUtil
{
// An extension method by Matt Johnson - on Stack Overflow at http://goo.gl/ymy7Wb
public static bool IsDaylightSavingsTime(this ZonedDateTime zonedDateTime)
{
var instant = zonedDateTime.ToInstant();
var zoneInterval = zonedDateTime.Zone.GetZoneInterval(instant);
return zoneInterval.Savings != Offset.Zero;
}
}

Problems with time

I coded this snippet to log the users IP and time on my website. It works but something is wrong with the time:
public static void UserLogin(string iPaddress, string uname)
{
DateTime dt = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now);
string cet= dt.AddHours(1).ToString("F", new CultureInfo("en-US"));
.....
}
The website is on a server somewhere in UK and to adjust the login time to CET without going too sophisticated, I simply toughth adding the hours difference using (AddHours) but for some reason, and I do not understand why, whatsoever number I put in there "AddHours(1)" will never get added and moreover, right now that is 13:55 at my location in Italy, the time recorder by the method is 1:55 am that is 12 hours behind even if there is no hours added "AddHours(0)".
Some help to understand what is going on in this method will be appreciated. Thanks.
You can convert time between time zones in more controlled way, for example:
DateTime nowutc = DateTime.UtcNow;
var cet = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
var nowcet = TimeZoneInfo.ConvertTimeFromUtc(nowutc, cet);

How to get Client Local Date from TimeZone in asp.net?

I have my database server located in U.S. The user makes entry from INDIA the date must be stored of client and not the server. but, unfortunately the server date is stored in database. I am showing the entries to user only of the current date that are made on the day only. Problem is when user enters record till 12:30 PM(Client Machine) are being displayed to user but after 12:30PM (Client Machine), the entries are not being displayed only the entries made after 12:30 PM(Client Machine) are displayed.Any Idea?
Eg: Entry done at 06/05/2013(DD/MM/YYYY) till 12:30 PM are shown when client machine date is 06/05/2013 11:57 AM
but when client machine date is 06/05/2013 12:57 PM the entries enterd are not displayed but entries made after 12:30 PM are displayed. In DB for above eg. created date is stored as 05/05/2013 don't know why?
In .cs file:
public static DateTime GetIndianDate(DateTime dateTime)
{
return TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dateTime, TimeZoneInfo.Local.Id,"India Standard Time").Date;
}
To show todays entries only:
shipments = BLL.GetShipmentsByUserIdNDate(userId, Classes.Common.GetIndianDate(DateTime.Now.Date));
public static List<Shipment> GetShipmentsByUserIdNDate(Guid userId, DateTime dateTime)
{
Entities db = new Entities();
List<Shipment> shipments = (from s in db.Shipments
where s.UserId == userId && s.CreatedDate == dateTime
select s).ToList();
return shipments;
}
While Inserting:
shipment.CreatedDate = Classes.Common.GetIndianDate(DateTime.Now.Date);
public static DateTime GetIndianDate(DateTime dateTime)
{
return TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dateTime, TimeZoneInfo.Local.Id,"India Standard Time").Date;
}
So, How will i store the date of client machine? now it still stores servers date only.
Help Appreciated!
Hey For same I Recommend to Store UTC Date time of every Record when You are saving the records.
When you are fetching the records please get the timezone and manipulate the UTC date
Select getutcdate() --Get UTC Date
Select getdate()--Get Indain Standared Date
Select dateadd(minute,30,dateadd(hour,5,getutcdate())) --Get Indian offset +05:30
If You want to Update your date from C# Code please refer this one.But in that case also required UTC date
string utcDateString = System.DateTime.UtcNow.ToString();
DateTime localDate = DateTime.Parse(utcDateString,
CultureInfo.CurrentCulture,
DateTimeStyles.AssumeUniversal);
Hop it Helps you.

asp.net timestamp issue

This i my code for storing record information from asp.net 2.0 webform
scmd.Connection = scon; //Connection string
SqlParameter p = scmd.CreateParameter();
recodName = txtrecordname.Text; //form field
todaysdate = DateTime.Parse(txtFrom.Text);
DateTime now = DateTime.UtcNow;
AddParameters("#record", recodName); //adding parameter to stored procedure
AddParameters("#date", todaysdate);
AddParameters("#timeinfo", now);
scmd.CommandText = "sp_InsertRecord";
scmd.CommandType = CommandType.StoredProcedure;
scon.Open();
int i=scmd.ExecuteNonQuery();
if (i > 0)
{
result.Text = "Record Inserted RecordName : " + recodName; //Label displaying recordinfo
dateinfo.Text = "Record inserted on (TimeStamp Info) : " + now; //label displaying time info when user inserted record
}
GridView1.DataBind();
This web application is hosted on server whose timezone is (UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi,
Now user from another system access the application whose time zone is (UTC+01:00) West Central Africa,
As you can see i have inserted 'datetime now as Utcnow' but when user view the record inserted it must be in its local datetimeformat
i.e
dateinfo.Text = "TimeStamp Info : " + now; //This label should display local time info currently it displays server local time where the application is hosted
Thanxs for any help
When loading the DateTime from the Database (you said you store UTC there), you need to specifiy the Kind of this time explicitely:
DateTime dateTimeFromDatabase = LoadDateTimeValueFromDatabase();
DateTime utcDate = DateTime.SpecifyKind(dateTimeFromDatabase, DateTimeKind.Utc);
Then, as long as you have the Culture of the web site visitor set correctly, you can simply use .ToLocalTime() from the DateTime to display the Utc value as local time:
DateTime localTimeToDisplay = utcDate.ToLocalTime();
You then use the localTimeToDisplay variable for databinding and you're all set.
Update: To display the current time you can simply do:
dateinfo.Text = "TimeStamp Info : " + DateTime.UtcNow.ToLocalTime();
As UtcNow already sets the Kind of DateTime to UTC.
You need to set the correct culture for the client, though. So you would need to do that either manually or set this in the web.config:
<system.web>
<globalization culture="auto" />
<system.web>
Use javascript to get the current time in the client system and put that in a javascript variable.
How to do it can be found here: http://www.quackit.com/javascript/javascript_date_and_time_functions.cfm
Then assign the javascript variable value to a hidden field variable and access it in the server side.
How to access javascript variable in code behind http://codeasp.net/blogs/joydeep157/microsoft-net/81/accessing-javascript-variable-from-code-behind-and-accessing-code-behind-variable-from-javascript
Now you have the client time in your server variable.

Resources