Commit 90e08b48 authored by Dan McGee's avatar Dan McGee
Browse files

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: default avatarDan McGee <dan@archlinux.org>
parent bc1ba4e9
......@@ -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
......
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':
......
# 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))
......
# 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):
......
......@@ -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
......
......@@ -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):
......
......@@ -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.
......
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(
......
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
......
......@@ -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)
......
# 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')
......
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,
......
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:
......
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)
......
......@@ -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
......
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)
......
{% extends "base.html" %}
{% load tz %}
{% block title %}Arch Linux - Developer World Clocks{% endblock %}
......@@ -10,7 +11,6 @@ <h2>Developer World Clocks</h2>
depends on developers keeping the time zone information up to date, so if
you see 'UTC' listed, pester them to update their settings.</p>
<p>
Arch Server Time: {{ now|date:"Y-m-d H:i T" }}<br/>
UTC Time: {{ utc_now|date:"Y-m-d H:i T" }}
</p>
......@@ -33,7 +33,7 @@ <h2>Developer World Clocks</h2>
<td>{{ dev.userprofile.alias }}</td>
<td>{{ dev.userprofile.location }}</td>
<td>{{ dev.userprofile.time_zone }}</td>
<td>{{ dev.current_time|date:"Y-m-d H:i T" }}</td>
<td>{{ utc_now|timezone:dev.userprofile.time_zone|date:"Y-m-d H:i T" }}</td>
</tr>
{% endfor %}
</tbody>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment