I am building a symfony2 app where the user can choose her timezone. I made the neseccary model/form changes to store a timezone field in the User object.
To apply the timezone inside a specific controller action I can just use:
$user = $this->get('security.context')->getToken()->getUser();
date_default_timezone_set( $user->getTimezone() );
Is there a way to do this without having to modify every controller/action?
This is an old question but the same answer still applies.
date_default_timezone_set should not be used in this manner. If you create a Datetime instance, the timezone will always be set to symfonys default timezone. This will lead to inconsistencies, I wish you the best of luck finding them :)
Basically, you should create a custom DateTime type that handles conversion of timezones. Additionally, if you really want different timezone on your server, set the timezone in config/parameters.yml so php handles all dates in the timezone you need.
parameters:
default_timezone: Europe/Warsaw
There's a nice tutorial here that will show you everything you need to know.
Related
Problem
If have Pojo with:
#JsonFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") // Note the 'Z' for timezone
Instant date;
I want the serialized JSON be presented in different timezone based on TimeZoneAwareLocaleContext
Description
I have multi-tenan Spring (boot) MVC application where each tenant defines timezone in which she would like to get her data.
I understand I can register TimeZoneAwareLocaleContext into LocaleContext and how to do it but I struggle to understand how (if even possible) force Jackson to serialize dates with respect to the LocalContext time-zone.
I also considered using custom tenant-aware Jackson serializer but it feels there might already be an out of box solution which I'm overlooking.
I need to write DateTime to database in UTC and convert it to users timezone upon retrieval. Every user has his timezone set in database.
Solution: Extend the Doctrine\DBAL\Types\DateTimeType as described here so it would always persist in UTC and when needed convert it back to user timezone in the presentation layer via Twig.
Problem: The suggested method converts UTC from the system default timezone. To make it work I need to read the actual user timezone in the extended DateTimeType and make conversions with that. So... I do the usual dependency injection and inject SecurityContext as it holds the User Entity together with the timezone value:
//TreasureForge\CoreBundle\DoctrineExtensions\DBAL\Types
private function __construct(SecurityContext $security)
{
$this->tz = $security->getToken()->getUser()->getTimezone();
}
and
treasure_forge.core_bundle.utc_datetime_extension:
class: TreasureForge\CoreBundle\DoctrineExtensions\DBAL\Types\UTCDateTimeType
arguments: ["#security.context"]
But it throws: Compile Error: Cannot override final method Doctrine\DBAL\Types\Type::__construct()
I've even resorted to the bad, bad methods like:
global $kernel;
$tz = $kernel->getContainer()->get('security.context')->getToken()->getUser()->getTimezone();
This is wrong in every imaginable way but even then for whatever reason getToken() is sometimes set and sometimes not throughout the request so I have serious doubts in the reliability of this.
Any ideas?
Did you try doing that in the Entity?
In your getDate() ( or whatever your getter is called ) you should get the user timezone. and again in the setter ( setDate() ) you should set whatever time you have to UTC.
Please write your Entity code to be able to provide an example.
In my play framework app the user has the choice to enter a date for a schedule, the date is then mapped to my model entity:
#InFuture
#As("dd/MM/yyyy HH:mm")
public Date validFrom;
This is the field in the form
<input type="text" name="schedule.validFrom" placeholder="dd/mm/yyyy hh:mm">
The problem is that our server is running in a non-local time zone and the timezone should be taken from the object where this schedule is being made for.
So I know upfront what the timezone is for this schedule and I don't want the user having to enter the timezone in the field.
A possible solution would be to submit the date as string and do manual validation and parsing but I wonder if there is a better solution.
Manual parsing is probably your best option.
You could possibly create your own object containing the date and the timezone.
Then implement your own validation check based on InFutureCheck and perform the timezone conversion.
The better option will be to give user a drop down list of timezones. For example:
String TIMEZONE_ID_PREFIXES ="^(Africa|America|Asia|Atlantic|Australia|Europe|Indian|Pacific)/.*";
String[] ids = TimeZone.getAvailableIDs();
Timezone tz = null;
for (int i=0; i<ids.length; i++) {
if (ids[i].matches(TIMEZONE_ID_PREFIXES)) {
//add TimeZone.getTimeZone(ids[i]).getDisplayName() to a drop down list
}
}
The best practice here really depends on whether your users need to see multiple timezones.
If they do not need multiple timezones, then you can assume all times are 'zone-less' aka they are all UTC or GMT. This is by far the simplest option.
If users need to see multiple timezones, then you are best off passing the timezone with each date with the Z parameter: http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html#rfc822timezone Meanwhile, in Javascript, you will probably want to use a library to create a date string with a timezone, such as: http://arshaw.com/xdate/#Formatting
There must be a simple way to get different timezones with code (ie without changeing your system timezone)
So far you can do something like
var timezone = TimeZone.CurrentTimeZone;
but I cant see any other way to get a different timezone?
or should I just use TimeSpan?
Actually it seems like it s a better idea to use TimeZoneInfo
Related answer
Creating a DateTime in a specific Time Zone in c# fx 3.5
how about using TimeZoneInfo.GetSystemTimeZones ?
This should return an array of all available TimeZone objects in this system.
how to ensure all my datetime is stored as UTC without going through all code? Does this have to be set in db ? how?
thanks.
In a web app, there are two ways that a non UTC DateTime can get into your database.
1) You did it. Search for all occurrences of DateTime.Now. Those need to be DateTime.UtcNow. Still, a find and replace isn't going to cover it all, because you'll need to update every place in your code where you display these dates to your users to convert them to local time.
2) Your user sent you a date/time. There's no automated way to look for these. You need to manually review every page that the user can use to pass a date/time. Either as data to be saved to your database or as a filter to be used in a query. You'll need to know their UTC offset and apply it to these occurrences before using them.
Be sure to capture the user's UTC offset as soon as they enter your site. As of now, the only way to do this is through javascript. If you have a single entry point (ie a login page) then you can put it there. Otherwise, you'll need to do it in your master page, or, if you don't have a master page, every page that they could enter on.
to get the UTC Offset in javascript use the following code:
var now = new Date();
int Offset = now.getTimezoneOffset()
Then pass the offset back to the server. There you can create two functions to handle converting from/to UTC.
Where UtcOffset holds the javascript Offset:
public static DateTime ConvertFromUtcToClientTime(DateTime utcDateTime)
{
return utcDateTime.AddMinutes(-UtcOffset);
}
public static DateTime ConvertFromClientTimeToUtc(DateTime clientDateTime)
{
return clientDateTime.AddMinutes(UtcOffset);
}