In a Django/Python application where I'm using redis, I do:
my_server = redis.Redis(connection_pool=POOL)
updated_at = time.time()
object_hash = "np:"+str(object_id)
sorted_set = "sn:"+str(user_id)
my_server.zadd(sorted_set, object_hash, updated_at)
This is straight forward. Essentially, I'm maintaining a sorted set that contains objects sorted by time of updating the object.
The problem is if I used redis-cli to get zrange sorted_set 0 -1 WITHSCORES, the score shows time that is precisely 5 hours older than what was originally in updated_at.
e.g. if updated_at was fed 1479646405.21, the redis sorted set score ends up being 1479628405.497179 (as per output from redis-cli). I.e. 5 hours behind. This looks like an issue of timezone - my location's ahead by 5 hours from UTC.
My question is: why does the score jump back 5 hours when updating the redis server? Whenever I print the updated_at variable from within my application, I get the correct number. Is this a Linux issue (the OS my application resides on is Ubuntu 14.04), and if so, can you explain precisely what could be going on? Being a beginner, I'm trying to understand the dynamics at play here. Thanks!
Related
I am continuing to practice on Data Camp and the current session covers Datetimes, timezone, dateutil, etc. However, there is a function I am not sure about. The function mentioned in the below code is .enfold() and I cannot seem to locate an easy explanation in the documentation. What is its general purpose and what is it doing in the Data Camp practice code below?
trip_durations = []
for trip in onebike_datetimes:
# When the start is later than the end, set the fold to be 1
if trip['start'] > trip['end']:
trip['end'] = tz.enfold(trip['end'])
# Convert to UTC
start = trip['start'].astimezone(tz.gettz('UTC'))
end = trip['end'].astimezone(tz.gettz('UTC'))
# Subtract the difference
trip_length_seconds = (end-start).total_seconds()
trip_durations.append(trip_length_seconds)
# Take the shortest trip duration
print("Shortest trip: " + str(min(trip_durations)))
I tried finding the documenatation for enfold directly under datetime documentation for Python but it kept mentioning "fold" under each of the functions/methods for the datetime package. Not super explanatory, so more information regarding .enfold() and "fold" in general would be helpful.
I am assuming that enfold in your code is the function from the tz module in the third-party timezone package: https://dateutil.readthedocs.io/en/stable/tz.html#dateutil.tz.enfold
As the documentation mentions, "fold" is an attribute of datetime objects whose implementation was changed in Python 3.6 by PEP 495. I cannot explain better what "fold" means than what is described in that document (unless my example below counts).
Apparently "fold" existed before Python 3.6, but was used/accessed in a different way. The tz.enfold function exists to unify the programming interface to the "fold" attribute regardless of the Python version used.
The specific application of "fold" in this code example seems to be the calculation of trip durations with "start" and "end" times. If an "end" time is found which seems to be earlier than the "start" time, it is deduced that the "end" time was recorded after a timezone change has occurred where the clocks were turned back by 1 hour, and the time is to be interpreted as the later of the two possible "real" times with that "local" or "wall" time. enfold(trip["end"]) returns a datetime object with the same local time as trip["end"] but with "fold" set to 1.
Example: Clocks are turned back at 3 AM to 2 AM
1 AM 2 AM 3 AM (4 AM)
-------|-------|--F-S--| - - - | - - > old local time
/
/
/
/
- - - | - - - |--E----|-------|-----> new local time
(1 AM) 2 AM 3 AM 4 AM
S: start - 2:40 AM (old local time)
E: end - 2:20 AM (new local time, fold=1, 40 minutes later than S)
F: false end - 2:20 AM (old local time, fold=0, 20 minutes earlier than S)
I have a Django application where users can setup stores. I recently added functionality to support opening hours following the advice on this thread - Business Opening hours in Django. My model looks like this:
class LocationHours(SafeDeleteModel):
location = models.ForeignKey(Location, related_name="hours", on_delete=models.CASCADE)
weekday = models.IntegerField(choices=WEEKDAYS, blank=False, null=False)
start_time = models.TimeField(blank=False, null=False, help_text="Opening time (00:00 format)")
end_time = models.TimeField(blank=False, null=False, help_text="Closing time (00:00 format)")
class Meta:
ordering = ('weekday', 'start_time')
unique_together = ('location', 'weekday', 'start_time', 'end_time')
verbose_name_plural = "Location hours"
Process goes like this - these times are entered in a form by the end user and thus assumed to be localtime, most datetimes/times being used in my application are in UTC. I need to compare the two often so originally, I thought I could figure out the timezone of each location object, then whenever I compare something to these OpeningHours, I can just use the given time and the tz (on the associated Location object) to calculate the time in UTC and then it's just a regular datetime comparison.
I wrote the following function to try and fix this:
def is_dt_within_location_hours(location, dt):
# see if time falls within hours
hours = location.hours
if hours.count() > 0:
for hour in hours.all():
dt = dt.astimezone(hour.location.timezone)
if dt.weekday() == hour.weekday:
if hour.start_time < dt.time() < hour.end_time:
return True
return False
else: # this location has no hours
return True
I thought this worked however has some issues.
Primary issue is this - when the Location objects are originally made or edited, I look up the timezone it's in (using the timezonefinder package) and store that in the Location object (using a TimeZoneField) at that time. This is to say, it will not auto update for DST or anything like that as far as I know. I could figure out the timezone everytime I call the above function however I call said function A LOT such that resource wise I'd like to say this is borderline not an option.
I imagine I could find a way to figure out the localtime at the moment they create an OpeningHours object and that way I could just convert to UTC and save it then but I don't know a good way to do that.
I'm thinking now I may need to scrap my entire solution and start from scratch but any advice is really helpful I've been struggling with this for a while.
You're doing it the right way.
You're worried about the timezone offset changing (as with DST) in between the time you record the Location and when you do the computation. But a timezone (represented by a name like "America/Chicago") isn't just an offset, it's a set of rules for computing the local time at any point in history. So it will do the right thing regardless of when you happened to record the timezone name.
A few other notes on the code you posted:
You probably want to make LocationHours unique on just location and weekeday, unless you're purposely trying to allow multiple opening hours for the same location on the same weekday.
Your is_dt_within_location_hours() is fairly inefficient. You don't need to fetch all the LocationHours objects and re-compute the weekday each time. Instead, first compute the local time, then filter location.hours to only include the LocationHours objects on that weekday.
I'm having trouble referencing outer fields from a django subquery in a way that would be pretty easy to do in SQL. I have these two models:
class Modem(models.Model):
mac = Models.LowerCaseCharField
class DHCPEvent(models.Model):
timestamp = models.DateTimeField() # date released
modem = models.ForeignKey(Modem)
ip = models.LowerCaseCharField()
The time window of when an IP is assigned to a given modem A is: [timestamp when IP assigned to modem A, timestamp when IP is assigned to another modem). I want to be able to query for all IP assignments to a specific modem overlapping a search time window (modem, from_date, to_date -> [ips]).
To do this, I believe I need to find DHCPEvents assigned to a modem before the time window ends, and then, for each one, confirm there is no DHCPEvent for its IP assigned elsewhere before the search time window starts. This defines that the IP-to-modem assignment overlaps with the search window. But I am not sure how to do this in Django. What I have so far is this:
Modem.objects.filter(
dhcpevent__ip=Subquery(
DHCPEvent.objects.filter(
ip=OuterRef('dhcpevent__ip'),
timestamp__gt=OuterRef('dhcpevent__timestamp'),
timestamp__lte=to_date)))
There are two issues:
It is throwing "ValueError: This queryset contains a reference to an outer query and may only be used in a subquery." It seems to be inside a subquery to me.
I need the OuterRefs to only look at the DHCPEvent first referenced in the second line, not every DHCPEvent attached to this Modem. But I don't know how to express this.
Any advice is appreciated. Thanks!
EDIT: I have now written this query in SQL which might clear up what I'm trying to achieve in Django a lot:
select
*
from
"MODEM" modem
inner join "DHCPEVENT" dhcp_event_assign
on modem."ID" = dhcp_event_assign."MODEM_ID"
where
modem."ID" = %(id)s
dhcp_event_assign."TIMESTAMP" <= %(to_date)s and
not exists(
select
*
from
"DHCPEVENT" dhcp_event_next
where
dhcp_event_next."REMOTE_ADDRESS" = dhcp_event_assign."REMOTE_ADDRESS"
and dhcp_event_next."TIMESTAMP" > dhcp_event_assign."TIMESTAMP"
and dhcp_event_next."TIMESTAMP" <= %(from_date)s
and not ( dhcp_event_next."MODEM_ID" = modem."ID" )
)
I have an Appengine app that still runs on the python2.5 runtime, which means it is single threaded. I have a school class:
class School(db.Model):
...
dateformat=db.StringProperty(default='%a %e %b',indexed=False) # For bookings
timeformat=db.StringProperty(default='%l:%M%P',indexed=False) # For bookings
def date(self,t):
return time.strftime(self.dateformat,time.gmtime(t))
def datetime(self,bt,et=None):
return time.strftime(self.dateformat+' '+self.timeformat,time.gmtime(bt))+\
(time.strftime(' - '+self.timeformat,time.gmtime(et)) if et else '')
def time(self,t):
return time.strftime(self.timeformat,time.gmtime(t))
Then when I want to format a date in the school's chosen format, I do this:
s=School.get_by_id(the_id)
date_string=s.date(the_timestamp)
Very occasionally, I get a date that is exactly a week out. So instead of "Wed 2 May" I get "Wed 9 May". This has been reported three times in the last week, out of probably tens of thousands of cases. All exactly a week out, none with any other time difference.
Nothing's changed in that part of my code for ages so I don't understand why this should suddenly start happening. Because it's single threaded, there shouldn't be issues with strftime, and I can't find any reports of thread issues with it anyway anyway.
Any ideas?
I've created the model for counting the number of views of my page:
class RequestCounter(models.Model):
count = models.IntegerField(default=0)
def __unicode__(self):
return str(self.count)
For incrementing the counter I use:
def inc_counter():
counter = RequestCounter.objects.get_or_create(id =1)[0]
counter.count = F('count') + 1
counter.save()
Then I show the number of the page views on my page and it works fine.
But now I need to cache my counter for some time. I use:
def get_view_count():
view_count = cache.get('v_count')
if view_count==None:
cache.set('v_count',RequestCounter.objects.filter(id = 1)[0],15)
view_count = cache.get('v_count')
return view_count
After this I'm passing the result of get_view_count to my template.
So I expect, that my counter would now stand still for 15 sec and then change to a new value. But, actually, it isn't quite so: when I'm testing this from my virtual ubuntu it jumps, for example, from 55 to 56, after 15 secs it changes and now jumps from 87 to 88.
The values are always alternating and they don't differ much from each other.
If I'm trying this locally from windows, the counter seems to be fine, until I try to open more than browser.
Got no idea what to do with it. Do you see what can be the problem?
p.s. i tried using caching in the templates - and received the same result.
What CACHE_BACKEND are you using? If it's locmem:// and you're running Apache, you'll have a different cache active for each Apache child, which would explain the differing results. I had this a while ago and it was a subtle one to work out. I'd recommend switching to memcache if you're not already on it, as this won't give you the multiple-caches problem