From 90e08b4863dfaecafee5b151478bda4513b12e85 Mon Sep 17 00:00:00 2001
From: Dan McGee
Date: Fri, 23 Mar 2012 19:29:40 -0500
Subject: Make all datetime objects fully timezone aware
This is most of the transition to Django 1.4 `USE_TZ = True`. We need to
ensure we don't mix aware and non-aware datetime objects when dealing
with datetimes in the code. Add a utc_now() helper method that we can
use most places, and ensure there is always a timezone attached when
necessary.
Signed-off-by: Dan McGee
---
devel/management/commands/reporead.py | 12 +++++---
devel/views.py | 33 +++++++++-------------
...mpressed_size__chg_field_package_installed_s.py | 5 +++-
.../0054_auto__add_field_donor_created.py | 5 +++-
main/models.py | 4 +--
main/utils.py | 12 ++++++--
mirrors/management/commands/mirrorcheck.py | 5 +++-
mirrors/utils.py | 13 +++++----
news/models.py | 7 +++--
packages/management/commands/signoff_report.py | 5 ++--
...0007_auto__add_field_packagerelation_created.py | 5 +++-
packages/views/flag.py | 5 ++--
packages/views/signoff.py | 4 +--
releng/management/commands/syncisos.py | 5 ++--
settings.py | 10 +++++--
sitemaps.py | 3 +-
templates/devel/clock.html | 4 +--
17 files changed, 80 insertions(+), 57 deletions(-)
diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py
index a8c58ba7..60ee6ec0 100644
--- a/devel/management/commands/reporead.py
+++ b/devel/management/commands/reporead.py
@@ -22,6 +22,7 @@
import logging
from datetime import datetime
from optparse import make_option
+from pytz import utc
from django.core.management.base import BaseCommand, CommandError
from django.db import connections, router, transaction
@@ -29,8 +30,10 @@
from devel.utils import UserFinder
from main.models import Arch, Package, PackageDepend, PackageFile, Repo
+from main.utils import utc_now
from packages.models import Conflict, Provision, Replacement
+
logging.basicConfig(
level=logging.WARNING,
format='%(asctime)s -> %(levelname)s: %(message)s',
@@ -113,7 +116,8 @@ def populate(self, values):
self.epoch = int(match.group(2))
elif k == 'builddate':
try:
- self.builddate = datetime.utcfromtimestamp(int(v[0]))
+ builddate = datetime.utcfromtimestamp(int(v[0]))
+ self.builddate = builddate.replace(tzinfo=utc)
except ValueError:
try:
self.builddate = datetime.strptime(v[0],
@@ -281,7 +285,7 @@ def populate_files(dbpkg, repopkg, force=False):
filename=filename)
pkg_files.append(pkgfile)
PackageFile.objects.bulk_create(pkg_files)
- dbpkg.files_last_update = datetime.utcnow()
+ dbpkg.files_last_update = utc_now()
dbpkg.save()
@@ -351,7 +355,7 @@ def db_update(archname, reponame, pkgs, force=False):
dbpkg = Package(pkgname=pkg.name, arch=architecture, repo=repository)
try:
with transaction.commit_on_success():
- populate_pkg(dbpkg, pkg, timestamp=datetime.utcnow())
+ populate_pkg(dbpkg, pkg, timestamp=utc_now())
except IntegrityError:
logger.warning("Could not add package %s; "
"not fatal if another thread beat us to it.",
@@ -378,7 +382,7 @@ def db_update(archname, reponame, pkgs, force=False):
if not force and pkg_same_version(pkg, dbpkg):
continue
elif not force:
- timestamp = datetime.utcnow()
+ timestamp = utc_now()
# The odd select_for_update song and dance here are to ensure
# simultaneous updates don't happen on a package, causing
diff --git a/devel/views.py b/devel/views.py
index 328d52e4..3a9be757 100644
--- a/devel/views.py
+++ b/devel/views.py
@@ -1,3 +1,10 @@
+from datetime import datetime, timedelta
+import operator
+import pytz
+import random
+from string import ascii_letters, digits
+import time
+
from django import forms
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import \
@@ -16,19 +23,13 @@
from django.utils.http import http_date
from main.models import Package, PackageDepend, PackageFile, TodolistPkg
-from main.models import Arch, Repo
-from main.models import UserProfile
+from main.models import Arch, Repo, UserProfile
+from main.utils import utc_now
from packages.models import PackageRelation
from packages.utils import get_signoff_groups
from todolists.utils import get_annotated_todolists
from .utils import get_annotated_maintainers
-from datetime import datetime, timedelta
-import operator
-import pytz
-import random
-from string import ascii_letters, digits
-import time
@login_required
def index(request):
@@ -85,22 +86,14 @@ def clock(request):
devs = User.objects.filter(is_active=True).order_by(
'first_name', 'last_name').select_related('userprofile')
- now = datetime.now()
- utc_now = datetime.utcnow().replace(tzinfo=pytz.utc)
- # now annotate each dev object with their current time
- for dev in devs:
- tz = pytz.timezone(dev.userprofile.time_zone)
- dev.current_time = utc_now.astimezone(tz)
-
+ now = utc_now()
page_dict = {
'developers': devs,
- 'now': now,
- 'utc_now': utc_now,
+ 'utc_now': now,
}
response = direct_to_template(request, 'devel/clock.html', page_dict)
if not response.has_header('Expires'):
- # why this works only with the non-UTC date I have no idea...
expire_time = now.replace(second=0, microsecond=0)
expire_time += timedelta(minutes=1)
expire_time = time.mktime(expire_time.timetuple())
@@ -168,12 +161,12 @@ def report(request, report_name, username=None):
if report_name == 'old':
title = 'Packages last built more than two years ago'
- cutoff = datetime.utcnow() - timedelta(days=365 * 2)
+ cutoff = utc_now() - timedelta(days=365 * 2)
packages = packages.filter(
build_date__lt=cutoff).order_by('build_date')
elif report_name == 'long-out-of-date':
title = 'Packages marked out-of-date more than 90 days ago'
- cutoff = datetime.utcnow() - timedelta(days=90)
+ cutoff = utc_now() - timedelta(days=90)
packages = packages.filter(
flag_date__lt=cutoff).order_by('flag_date')
elif report_name == 'big':
diff --git a/main/migrations/0050_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py b/main/migrations/0050_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py
index 7aa09596..8368ae2e 100644
--- a/main/migrations/0050_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py
+++ b/main/migrations/0050_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py
@@ -1,5 +1,6 @@
# encoding: utf-8
import datetime
+from pytz import utc
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
@@ -9,7 +10,9 @@ class Migration(SchemaMigration):
def forwards(self, orm):
db.alter_column('packages', 'compressed_size', self.gf('main.models.PositiveBigIntegerField')(default=0))
db.alter_column('packages', 'installed_size', self.gf('main.models.PositiveBigIntegerField')(default=0))
- db.alter_column('packages', 'last_update', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2000, 1, 1)))
+ old_date = datetime.datetime(2000, 1, 1)
+ old_date = old_date.replace(tzinfo=utc)
+ db.alter_column('packages', 'last_update', self.gf('django.db.models.fields.DateTimeField')(default=old_date))
def backwards(self, orm):
db.alter_column('packages', 'compressed_size', self.gf('django.db.models.fields.BigIntegerField')(null=True))
diff --git a/main/migrations/0054_auto__add_field_donor_created.py b/main/migrations/0054_auto__add_field_donor_created.py
index f4d5b157..c96c0f5d 100644
--- a/main/migrations/0054_auto__add_field_donor_created.py
+++ b/main/migrations/0054_auto__add_field_donor_created.py
@@ -1,5 +1,6 @@
# encoding: utf-8
import datetime
+from pytz import utc
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
@@ -8,7 +9,9 @@ class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Donor.created'
- db.add_column('donors', 'created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.date(2000, 1, 1)), keep_default=False)
+ old_date = datetime.datetime(2000, 1, 1)
+ old_date = old_date.replace(tzinfo=utc)
+ db.add_column('donors', 'created', self.gf('django.db.models.fields.DateTimeField')(default=old_date), keep_default=False)
def backwards(self, orm):
diff --git a/main/models.py b/main/models.py
index 4f2d64ea..7d017242 100644
--- a/main/models.py
+++ b/main/models.py
@@ -9,7 +9,7 @@
from django.contrib.sites.models import Site
from .fields import PositiveBigIntegerField, PGPKeyField
-from .utils import cache_function, make_choice, set_created_field
+from .utils import cache_function, make_choice, set_created_field, utc_now
class UserProfile(models.Model):
@@ -515,7 +515,7 @@ class Meta:
def set_todolist_fields(sender, **kwargs):
todolist = kwargs['instance']
if not todolist.date_added:
- todolist.date_added = datetime.utcnow()
+ todolist.date_added = utc_now()
# connect signals needed to keep cache in line with reality
from main.utils import refresh_latest
diff --git a/main/utils.py b/main/utils.py
index 8143ea6a..e7e47c53 100644
--- a/main/utils.py
+++ b/main/utils.py
@@ -5,6 +5,7 @@
from datetime import datetime
import hashlib
+from pytz import utc
from django.core.cache import cache
@@ -91,12 +92,17 @@ def retrieve_latest(sender):
return None
+def utc_now():
+ '''Returns a timezone-aware UTC date representing now.'''
+ return datetime.utcnow().replace(tzinfo=utc)
+
+
def set_created_field(sender, **kwargs):
- '''This will set the 'created' field on any object to datetime.utcnow() if
- it is unset. For use as a pre_save signal handler.'''
+ '''This will set the 'created' field on any object to the current UTC time
+ if it is unset. For use as a pre_save signal handler.'''
obj = kwargs['instance']
if hasattr(obj, 'created') and not obj.created:
- obj.created = datetime.utcnow()
+ obj.created = utc_now()
def groupby_preserve_order(iterable, keyfunc):
diff --git a/mirrors/management/commands/mirrorcheck.py b/mirrors/management/commands/mirrorcheck.py
index 8eb8b010..c2928e67 100644
--- a/mirrors/management/commands/mirrorcheck.py
+++ b/mirrors/management/commands/mirrorcheck.py
@@ -21,9 +21,11 @@
import time
from threading import Thread
import types
+from pytz import utc
from Queue import Queue, Empty
import urllib2
+from main.utils import utc_now
from mirrors.models import MirrorUrl, MirrorLog
logging.basicConfig(
@@ -50,7 +52,7 @@ def handle_noargs(self, **options):
def check_mirror_url(mirror_url):
url = mirror_url.url + 'lastsync'
logger.info("checking URL %s", url)
- log = MirrorLog(url=mirror_url, check_time=datetime.utcnow())
+ log = MirrorLog(url=mirror_url, check_time=utc_now())
try:
start = time.time()
result = urllib2.urlopen(url, timeout=10)
@@ -61,6 +63,7 @@ def check_mirror_url(mirror_url):
parsed_time = None
try:
parsed_time = datetime.utcfromtimestamp(int(data))
+ parsed_time = parsed_time.replace(tzinfo=utc)
except ValueError:
# it is bad news to try logging the lastsync value;
# sometimes we get a crazy-encoded web page.
diff --git a/mirrors/utils.py b/mirrors/utils.py
index f05ffc77..0f8fef84 100644
--- a/mirrors/utils.py
+++ b/mirrors/utils.py
@@ -1,11 +1,12 @@
+from datetime import timedelta
+
from django.db.models import Avg, Count, Max, Min, StdDev
-from main.utils import cache_function
+from main.utils import cache_function, utc_now
from .models import MirrorLog, MirrorProtocol, MirrorUrl
-import datetime
-default_cutoff = datetime.timedelta(hours=24)
+default_cutoff = timedelta(hours=24)
def annotate_url(url, delays):
'''Given a MirrorURL object, add a few more attributes to it regarding
@@ -13,7 +14,7 @@ def annotate_url(url, delays):
url.completion_pct = float(url.success_count) / url.check_count
if url.id in delays:
url_delays = delays[url.id]
- url.delay = sum(url_delays, datetime.timedelta()) / len(url_delays)
+ url.delay = sum(url_delays, timedelta()) / len(url_delays)
hours = url.delay.days * 24.0 + url.delay.seconds / 3600.0
if url.completion_pct > 0:
@@ -28,7 +29,7 @@ def annotate_url(url, delays):
@cache_function(123)
def get_mirror_statuses(cutoff=default_cutoff):
- cutoff_time = datetime.datetime.utcnow() - cutoff
+ cutoff_time = utc_now() - cutoff
protocols = list(MirrorProtocol.objects.filter(is_download=True))
# I swear, this actually has decent performance...
urls = MirrorUrl.objects.select_related('mirror', 'protocol').filter(
@@ -82,7 +83,7 @@ def get_mirror_statuses(cutoff=default_cutoff):
@cache_function(117)
def get_mirror_errors(cutoff=default_cutoff):
- cutoff_time = datetime.datetime.utcnow() - cutoff
+ cutoff_time = utc_now() - cutoff
errors = MirrorLog.objects.filter(
is_success=False, check_time__gte=cutoff_time,
url__mirror__active=True, url__mirror__public=True).values(
diff --git a/news/models.py b/news/models.py
index 33d958e0..95026e1d 100644
--- a/news/models.py
+++ b/news/models.py
@@ -1,9 +1,10 @@
-from datetime import datetime
-
from django.db import models
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
+from main.utils import utc_now
+
+
class News(models.Model):
slug = models.SlugField(max_length=255, unique=True)
author = models.ForeignKey(User, related_name='news_author',
@@ -28,7 +29,7 @@ class Meta:
def set_news_fields(sender, **kwargs):
news = kwargs['instance']
- now = datetime.utcnow()
+ now = utc_now()
news.last_modified = now
if not news.postdate:
news.postdate = now
diff --git a/packages/management/commands/signoff_report.py b/packages/management/commands/signoff_report.py
index 3b67f518..ddf930db 100644
--- a/packages/management/commands/signoff_report.py
+++ b/packages/management/commands/signoff_report.py
@@ -17,12 +17,13 @@
from django.template import loader, Context
from collections import namedtuple
-from datetime import datetime, timedelta
+from datetime import timedelta
import logging
from operator import attrgetter
import sys
from main.models import Repo
+from main.utils import utc_now
from packages.models import Signoff
from packages.utils import get_signoff_groups
@@ -65,7 +66,7 @@ def generate_report(email, repo_name):
new_hours = 24
old_days = 14
- now = datetime.utcnow()
+ now = utc_now()
new_cutoff = now - timedelta(hours=new_hours)
old_cutoff = now - timedelta(days=old_days)
diff --git a/packages/migrations/0007_auto__add_field_packagerelation_created.py b/packages/migrations/0007_auto__add_field_packagerelation_created.py
index 37321fdb..b030909e 100644
--- a/packages/migrations/0007_auto__add_field_packagerelation_created.py
+++ b/packages/migrations/0007_auto__add_field_packagerelation_created.py
@@ -1,5 +1,6 @@
# encoding: utf-8
import datetime
+from pytz import utc
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
@@ -7,7 +8,9 @@
class Migration(SchemaMigration):
def forwards(self, orm):
- db.add_column('packages_packagerelation', 'created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.utcnow()), keep_default=False)
+ old_date = datetime.datetime(2000, 1, 1)
+ old_date = old_date.replace(tzinfo=utc)
+ db.add_column('packages_packagerelation', 'created', self.gf('django.db.models.fields.DateTimeField')(default=old_date), keep_default=False)
def backwards(self, orm):
db.delete_column('packages_packagerelation', 'created')
diff --git a/packages/views/flag.py b/packages/views/flag.py
index c0990e8e..0d2f9009 100644
--- a/packages/views/flag.py
+++ b/packages/views/flag.py
@@ -1,5 +1,3 @@
-from datetime import datetime
-
from django import forms
from django.conf import settings
from django.contrib.auth.decorators import permission_required
@@ -12,6 +10,7 @@
from ..models import FlagRequest
from main.models import Package
+from main.utils import utc_now
def flaghelp(request):
@@ -61,7 +60,7 @@ def flag(request, name, repo, arch):
@transaction.commit_on_success
def perform_updates():
- now = datetime.utcnow()
+ now = utc_now()
pkgs.update(flag_date=now)
# store our flag request
flag_request = FlagRequest(created=now,
diff --git a/packages/views/signoff.py b/packages/views/signoff.py
index e3daf0dd..cf00b0b9 100644
--- a/packages/views/signoff.py
+++ b/packages/views/signoff.py
@@ -1,4 +1,3 @@
-from datetime import datetime
from operator import attrgetter
from django import forms
@@ -13,6 +12,7 @@
from django.views.generic.simple import direct_to_template
from main.models import Package, Arch, Repo
+from main.utils import utc_now
from ..models import SignoffSpecification, Signoff
from ..utils import (get_signoff_groups, approved_by_signoffs,
PackageSignoffGroup)
@@ -45,7 +45,7 @@ def signoff_package(request, name, repo, arch, revoke=False):
package, request.user, False)
except Signoff.DoesNotExist:
raise Http404
- signoff.revoked = datetime.utcnow()
+ signoff.revoked = utc_now()
signoff.save()
created = False
else:
diff --git a/releng/management/commands/syncisos.py b/releng/management/commands/syncisos.py
index 270c6c34..62f005ff 100644
--- a/releng/management/commands/syncisos.py
+++ b/releng/management/commands/syncisos.py
@@ -1,4 +1,3 @@
-from datetime import datetime
import re
import urllib
from HTMLParser import HTMLParser, HTMLParseError
@@ -6,8 +5,10 @@
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
+from main.utils import utc_now
from releng.models import Iso
+
class IsoListParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
@@ -53,7 +54,7 @@ def handle(self, *args, **options):
existing.active = True
existing.removed = None
existing.save()
- now = datetime.utcnow()
+ now = utc_now()
# and then mark all other names as no longer active
Iso.objects.filter(active=True).exclude(name__in=active_isos).update(
active=False, removed=now)
diff --git a/settings.py b/settings.py
index 9aba3881..e1d4d4a9 100644
--- a/settings.py
+++ b/settings.py
@@ -18,9 +18,13 @@
# Full path to the data directory
DEPLOY_PATH = os.path.dirname(os.path.realpath(__file__))
-# Local time zone for this installation. All choices can be found here:
-# http://www.postgresql.org/docs/current/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
-TIME_ZONE = 'US/Eastern'
+# If you set this to False, Django will not use timezone-aware datetimes.
+USE_TZ = True
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+TIME_ZONE = 'UTC'
# Language code for this installation. All choices can be found here:
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
diff --git a/sitemaps.py b/sitemaps.py
index 177555ff..8e9ba36f 100644
--- a/sitemaps.py
+++ b/sitemaps.py
@@ -1,4 +1,5 @@
from datetime import datetime, timedelta
+from pytz import utc
from django.contrib.sitemaps import Sitemap
from django.core.urlresolvers import reverse
@@ -62,7 +63,7 @@ class NewsSitemap(Sitemap):
priority = "0.8"
def __init__(self):
- now = datetime.utcnow()
+ now = datetime.utcnow().replace(tzinfo=utc)
self.one_day_ago = now - timedelta(days=1)
self.one_week_ago = now - timedelta(days=7)
diff --git a/templates/devel/clock.html b/templates/devel/clock.html
index 72a57d0f..3b00075f 100644
--- a/templates/devel/clock.html
+++ b/templates/devel/clock.html
@@ -1,4 +1,5 @@
{% extends "base.html" %}
+{% load tz %}
{% block title %}Arch Linux - Developer World Clocks{% endblock %}
@@ -10,7 +11,6 @@ Developer World Clocks
depends on developers keeping the time zone information up to date, so if
you see 'UTC' listed, pester them to update their settings.
- Arch Server Time: {{ now|date:"Y-m-d H:i T" }}
UTC Time: {{ utc_now|date:"Y-m-d H:i T" }}
@@ -33,7 +33,7 @@ Developer World Clocks
{{ dev.userprofile.alias }} |
{{ dev.userprofile.location }} |
{{ dev.userprofile.time_zone }} |
- {{ dev.current_time|date:"Y-m-d H:i T" }} |
+ {{ utc_now|timezone:dev.userprofile.time_zone|date:"Y-m-d H:i T" }} |
{% endfor %}
--
cgit v1.2.3-54-g00ecf