Browse Source

Convert naive datetime objects to non naive ones

sh4nks 8 years ago
parent
commit
8ef577d754

+ 4 - 5
flaskbb/app.py

@@ -10,7 +10,6 @@
 """
 """
 import os
 import os
 import logging
 import logging
-import datetime
 import time
 import time
 from functools import partial
 from functools import partial
 
 
@@ -34,10 +33,10 @@ from flaskbb.extensions import (db, login_manager, mail, cache, redis_store,
                                 debugtoolbar, migrate, themes, plugin_manager,
                                 debugtoolbar, migrate, themes, plugin_manager,
                                 babel, csrf, allows, limiter, celery)
                                 babel, csrf, allows, limiter, celery)
 # various helpers
 # various helpers
-from flaskbb.utils.helpers import (format_date, time_since, crop_title,
-                                   is_online, render_markup, mark_online,
+from flaskbb.utils.helpers import (time_utcnow, format_date, time_since,
+                                   crop_title, is_online, mark_online,
                                    forum_is_unread, topic_is_unread,
                                    forum_is_unread, topic_is_unread,
-                                   render_template)
+                                   render_template, render_markup)
 from flaskbb.utils.translations import FlaskBBDomain
 from flaskbb.utils.translations import FlaskBBDomain
 # permission checks (here they are used for the jinja filters)
 # permission checks (here they are used for the jinja filters)
 from flaskbb.utils.requirements import (IsAdmin, IsAtleastModerator,
 from flaskbb.utils.requirements import (IsAdmin, IsAtleastModerator,
@@ -238,7 +237,7 @@ def configure_before_handlers(app):
         authenticated."""
         authenticated."""
 
 
         if current_user.is_authenticated:
         if current_user.is_authenticated:
-            current_user.lastseen = datetime.datetime.utcnow()
+            current_user.lastseen = time_utcnow()
             db.session.add(current_user)
             db.session.add(current_user)
             db.session.commit()
             db.session.commit()
 
 

+ 3 - 3
flaskbb/auth/forms.py

@@ -8,15 +8,15 @@
     :copyright: (c) 2014 by the FlaskBB Team.
     :copyright: (c) 2014 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
-from datetime import datetime
-
 from flask_wtf import Form
 from flask_wtf import Form
 from wtforms import (StringField, PasswordField, BooleanField, HiddenField,
 from wtforms import (StringField, PasswordField, BooleanField, HiddenField,
                      SubmitField, SelectField)
                      SubmitField, SelectField)
 from wtforms.validators import (DataRequired, InputRequired, Email, EqualTo,
 from wtforms.validators import (DataRequired, InputRequired, Email, EqualTo,
                                 regexp, ValidationError)
                                 regexp, ValidationError)
 from flask_babelplus import lazy_gettext as _
 from flask_babelplus import lazy_gettext as _
+
 from flaskbb.user.models import User
 from flaskbb.user.models import User
+from flaskbb.utils.helpers import time_utcnow
 from flaskbb.utils.recaptcha import RecaptchaField
 from flaskbb.utils.recaptcha import RecaptchaField
 
 
 USERNAME_RE = r'^[\w.+-]+$'
 USERNAME_RE = r'^[\w.+-]+$'
@@ -76,7 +76,7 @@ class RegisterForm(Form):
         user = User(username=self.username.data,
         user = User(username=self.username.data,
                     email=self.email.data,
                     email=self.email.data,
                     password=self.password.data,
                     password=self.password.data,
-                    date_joined=datetime.utcnow(),
+                    date_joined=time_utcnow(),
                     primary_group_id=4,
                     primary_group_id=4,
                     language=self.language.data)
                     language=self.language.data)
         return user.save()
         return user.save()

+ 24 - 23
flaskbb/forum/models.py

@@ -8,15 +8,15 @@
     :copyright: (c) 2014 by the FlaskBB Team.
     :copyright: (c) 2014 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
-from datetime import datetime, timedelta
+from datetime import timedelta
 
 
 from flask import url_for, abort
 from flask import url_for, abort
 from sqlalchemy.orm import aliased
 from sqlalchemy.orm import aliased
 
 
 from flaskbb.extensions import db
 from flaskbb.extensions import db
 from flaskbb.utils.helpers import (slugify, get_categories_and_forums,
 from flaskbb.utils.helpers import (slugify, get_categories_and_forums,
-                                   get_forums)
-from flaskbb.utils.database import CRUDMixin
+                                   get_forums, time_utcnow)
+from flaskbb.utils.database import CRUDMixin, UTCDateTime
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.settings import flaskbb_config
 
 
 
 
@@ -70,7 +70,7 @@ class TopicsRead(db.Model, CRUDMixin):
                          db.ForeignKey("forums.id", use_alter=True,
                          db.ForeignKey("forums.id", use_alter=True,
                                        name="fk_tr_forum_id"),
                                        name="fk_tr_forum_id"),
                          primary_key=True)
                          primary_key=True)
-    last_read = db.Column(db.DateTime, default=datetime.utcnow())
+    last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
 
 
 
 
 class ForumsRead(db.Model, CRUDMixin):
 class ForumsRead(db.Model, CRUDMixin):
@@ -82,8 +82,8 @@ class ForumsRead(db.Model, CRUDMixin):
                          db.ForeignKey("forums.id", use_alter=True,
                          db.ForeignKey("forums.id", use_alter=True,
                                        name="fk_fr_forum_id"),
                                        name="fk_fr_forum_id"),
                          primary_key=True)
                          primary_key=True)
-    last_read = db.Column(db.DateTime, default=datetime.utcnow())
-    cleared = db.Column(db.DateTime)
+    last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
+    cleared = db.Column(UTCDateTime(timezone=True))
 
 
 
 
 class Report(db.Model, CRUDMixin):
 class Report(db.Model, CRUDMixin):
@@ -92,9 +92,9 @@ class Report(db.Model, CRUDMixin):
     id = db.Column(db.Integer, primary_key=True)
     id = db.Column(db.Integer, primary_key=True)
     reporter_id = db.Column(db.Integer, db.ForeignKey("users.id"),
     reporter_id = db.Column(db.Integer, db.ForeignKey("users.id"),
                             nullable=False)
                             nullable=False)
-    reported = db.Column(db.DateTime, default=datetime.utcnow())
+    reported = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
     post_id = db.Column(db.Integer, db.ForeignKey("posts.id"), nullable=False)
     post_id = db.Column(db.Integer, db.ForeignKey("posts.id"), nullable=False)
-    zapped = db.Column(db.DateTime)
+    zapped = db.Column(UTCDateTime(timezone=True))
     zapped_by = db.Column(db.Integer, db.ForeignKey("users.id"))
     zapped_by = db.Column(db.Integer, db.ForeignKey("users.id"))
     reason = db.Column(db.Text)
     reason = db.Column(db.Text)
 
 
@@ -121,7 +121,7 @@ class Report(db.Model, CRUDMixin):
 
 
         if post and user:
         if post and user:
             self.reporter_id = user.id
             self.reporter_id = user.id
-            self.reported = datetime.utcnow()
+            self.reported = time_utcnow()
             self.post_id = post.id
             self.post_id = post.id
 
 
         db.session.add(self)
         db.session.add(self)
@@ -142,8 +142,8 @@ class Post(db.Model, CRUDMixin):
     user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
     user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
     username = db.Column(db.String(200), nullable=False)
     username = db.Column(db.String(200), nullable=False)
     content = db.Column(db.Text, nullable=False)
     content = db.Column(db.Text, nullable=False)
-    date_created = db.Column(db.DateTime, default=datetime.utcnow())
-    date_modified = db.Column(db.DateTime)
+    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
+    date_modified = db.Column(UTCDateTime(timezone=True))
     modified_by = db.Column(db.String(200))
     modified_by = db.Column(db.String(200))
 
 
     # Properties
     # Properties
@@ -180,7 +180,7 @@ class Post(db.Model, CRUDMixin):
 
 
         # Adding a new post
         # Adding a new post
         if user and topic:
         if user and topic:
-            created = datetime.utcnow()
+            created = time_utcnow()
             self.user_id = user.id
             self.user_id = user.id
             self.username = user.username
             self.username = user.username
             self.topic_id = topic.id
             self.topic_id = topic.id
@@ -270,8 +270,8 @@ class Topic(db.Model, CRUDMixin):
     title = db.Column(db.String(255), nullable=False)
     title = db.Column(db.String(255), nullable=False)
     user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
     user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
     username = db.Column(db.String(200), nullable=False)
     username = db.Column(db.String(200), nullable=False)
-    date_created = db.Column(db.DateTime, default=datetime.utcnow())
-    last_updated = db.Column(db.DateTime, default=datetime.utcnow())
+    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
+    last_updated = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
     locked = db.Column(db.Boolean, default=False)
     locked = db.Column(db.Boolean, default=False)
     important = db.Column(db.Boolean, default=False)
     important = db.Column(db.Boolean, default=False)
     views = db.Column(db.Integer, default=0)
     views = db.Column(db.Integer, default=0)
@@ -340,7 +340,7 @@ class Topic(db.Model, CRUDMixin):
         """
         """
         read_cutoff = None
         read_cutoff = None
         if flaskbb_config['TRACKER_LENGTH'] > 0:
         if flaskbb_config['TRACKER_LENGTH'] > 0:
-            read_cutoff = datetime.utcnow() - timedelta(
+            read_cutoff = time_utcnow() - timedelta(
                 days=flaskbb_config['TRACKER_LENGTH'])
                 days=flaskbb_config['TRACKER_LENGTH'])
 
 
         # The tracker is disabled - abort
         # The tracker is disabled - abort
@@ -391,7 +391,7 @@ class Topic(db.Model, CRUDMixin):
         # A new post has been submitted that the user hasn't read.
         # A new post has been submitted that the user hasn't read.
         # Updating...
         # Updating...
         if topicsread:
         if topicsread:
-            topicsread.last_read = datetime.utcnow()
+            topicsread.last_read = time_utcnow()
             topicsread.save()
             topicsread.save()
             updated = True
             updated = True
 
 
@@ -402,7 +402,7 @@ class Topic(db.Model, CRUDMixin):
             topicsread.user_id = user.id
             topicsread.user_id = user.id
             topicsread.topic_id = self.id
             topicsread.topic_id = self.id
             topicsread.forum_id = self.forum_id
             topicsread.forum_id = self.forum_id
-            topicsread.last_read = datetime.utcnow()
+            topicsread.last_read = time_utcnow()
             topicsread.save()
             topicsread.save()
             updated = True
             updated = True
 
 
@@ -471,9 +471,9 @@ class Topic(db.Model, CRUDMixin):
         self.username = user.username
         self.username = user.username
 
 
         # Set the last_updated time. Needed for the readstracker
         # Set the last_updated time. Needed for the readstracker
-        self.last_updated = datetime.utcnow()
+        self.last_updated = time_utcnow()
 
 
-        self.date_created = datetime.utcnow()
+        self.date_created = time_utcnow()
 
 
         # Insert and commit the topic
         # Insert and commit the topic
         db.session.add(self)
         db.session.add(self)
@@ -577,7 +577,8 @@ class Forum(db.Model, CRUDMixin):
     last_post_title = db.Column(db.String(255))
     last_post_title = db.Column(db.String(255))
     last_post_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
     last_post_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
     last_post_username = db.Column(db.String(255))
     last_post_username = db.Column(db.String(255))
-    last_post_created = db.Column(db.DateTime, default=datetime.utcnow())
+    last_post_created = db.Column(UTCDateTime(timezone=True),
+                                  default=time_utcnow())
 
 
     # One-to-many
     # One-to-many
     topics = db.relationship(
     topics = db.relationship(
@@ -681,7 +682,7 @@ class Forum(db.Model, CRUDMixin):
 
 
         read_cutoff = None
         read_cutoff = None
         if flaskbb_config['TRACKER_LENGTH'] > 0:
         if flaskbb_config['TRACKER_LENGTH'] > 0:
-            read_cutoff = datetime.utcnow() - timedelta(
+            read_cutoff = time_utcnow() - timedelta(
                 days=flaskbb_config['TRACKER_LENGTH'])
                 days=flaskbb_config['TRACKER_LENGTH'])
 
 
         # fetch the unread posts in the forum
         # fetch the unread posts in the forum
@@ -708,7 +709,7 @@ class Forum(db.Model, CRUDMixin):
             # has been submitted and has read everything (obviously, else the
             # has been submitted and has read everything (obviously, else the
             # unread_count would be useless).
             # unread_count would be useless).
             elif forumsread:
             elif forumsread:
-                forumsread.last_read = datetime.utcnow()
+                forumsread.last_read = time_utcnow()
                 forumsread.save()
                 forumsread.save()
                 return True
                 return True
 
 
@@ -716,7 +717,7 @@ class Forum(db.Model, CRUDMixin):
             forumsread = ForumsRead()
             forumsread = ForumsRead()
             forumsread.user_id = user.id
             forumsread.user_id = user.id
             forumsread.forum_id = self.id
             forumsread.forum_id = self.id
-            forumsread.last_read = datetime.utcnow()
+            forumsread.last_read = time_utcnow()
             forumsread.save()
             forumsread.save()
             return True
             return True
 
 

+ 9 - 12
flaskbb/forum/views.py

@@ -9,25 +9,22 @@
     :copyright: (c) 2014 by the FlaskBB Team.
     :copyright: (c) 2014 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
-import datetime
-
 from sqlalchemy import asc, desc
 from sqlalchemy import asc, desc
 from flask import Blueprint, redirect, url_for, current_app, request, flash
 from flask import Blueprint, redirect, url_for, current_app, request, flash
 from flask_login import login_required, current_user
 from flask_login import login_required, current_user
 from flask_babelplus import gettext as _
 from flask_babelplus import gettext as _
 from flask_allows import Permission, And
 from flask_allows import Permission, And
+
 from flaskbb.extensions import db, allows
 from flaskbb.extensions import db, allows
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.settings import flaskbb_config
-from flaskbb.utils.helpers import (get_online_users, time_diff, format_quote,
-                                   render_template, do_topic_action)
-
+from flaskbb.utils.helpers import (get_online_users, time_diff, time_utcnow,
+                                   format_quote, render_template,
+                                   do_topic_action)
 from flaskbb.utils.requirements import (CanAccessForum, CanAccessTopic,
 from flaskbb.utils.requirements import (CanAccessForum, CanAccessTopic,
                                         CanDeletePost, CanDeleteTopic,
                                         CanDeletePost, CanDeleteTopic,
                                         CanEditPost, CanPostReply,
                                         CanEditPost, CanPostReply,
                                         CanPostTopic,
                                         CanPostTopic,
                                         IsAtleastModeratorInForum)
                                         IsAtleastModeratorInForum)
-
-
 from flaskbb.forum.models import (Category, Forum, Topic, Post, ForumsRead,
 from flaskbb.forum.models import (Category, Forum, Topic, Post, ForumsRead,
                                   TopicsRead)
                                   TopicsRead)
 from flaskbb.forum.forms import (NewTopicForm, QuickreplyForm, ReplyForm,
 from flaskbb.forum.forms import (NewTopicForm, QuickreplyForm, ReplyForm,
@@ -444,7 +441,7 @@ def edit_post(post_id):
             )
             )
         else:
         else:
             form.populate_obj(post)
             form.populate_obj(post)
-            post.date_modified = datetime.datetime.utcnow()
+            post.date_modified = time_utcnow()
             post.modified_by = current_user.username
             post.modified_by = current_user.username
             post.save()
             post.save()
             return redirect(post.topic.url)
             return redirect(post.topic.url)
@@ -516,8 +513,8 @@ def markread(forum_id=None, slug=None):
             forumsread.user_id = current_user.id
             forumsread.user_id = current_user.id
             forumsread.forum_id = forum_instance.id
             forumsread.forum_id = forum_instance.id
 
 
-        forumsread.last_read = datetime.datetime.utcnow()
-        forumsread.cleared = datetime.datetime.utcnow()
+        forumsread.last_read = time_utcnow()
+        forumsread.cleared = time_utcnow()
 
 
         db.session.add(forumsread)
         db.session.add(forumsread)
         db.session.commit()
         db.session.commit()
@@ -537,8 +534,8 @@ def markread(forum_id=None, slug=None):
         forumsread = ForumsRead()
         forumsread = ForumsRead()
         forumsread.user_id = current_user.id
         forumsread.user_id = current_user.id
         forumsread.forum_id = forum_instance.id
         forumsread.forum_id = forum_instance.id
-        forumsread.last_read = datetime.datetime.utcnow()
-        forumsread.cleared = datetime.datetime.utcnow()
+        forumsread.last_read = time_utcnow()
+        forumsread.cleared = time_utcnow()
         forumsread_list.append(forumsread)
         forumsread_list.append(forumsread)
 
 
     db.session.add_all(forumsread_list)
     db.session.add_all(forumsread_list)

+ 5 - 5
flaskbb/management/views.py

@@ -9,7 +9,6 @@
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
 import sys
 import sys
-from datetime import datetime
 
 
 from flask import (Blueprint, current_app, request, redirect, url_for, flash,
 from flask import (Blueprint, current_app, request, redirect, url_for, flash,
                    jsonify, __version__ as flask_version)
                    jsonify, __version__ as flask_version)
@@ -26,7 +25,8 @@ from flaskbb.utils.requirements import (IsAtleastModerator, IsAdmin,
                                         CanBanUser, CanEditUser,
                                         CanBanUser, CanEditUser,
                                         IsAtleastSuperModerator)
                                         IsAtleastSuperModerator)
 from flaskbb.extensions import db, allows
 from flaskbb.extensions import db, allows
-from flaskbb.utils.helpers import render_template, time_diff, get_online_users
+from flaskbb.utils.helpers import (render_template, time_diff, time_utcnow,
+                                   get_online_users)
 from flaskbb.user.models import Guest, User, Group
 from flaskbb.user.models import Guest, User, Group
 from flaskbb.forum.models import Post, Topic, Forum, Category, Report
 from flaskbb.forum.models import Post, Topic, Forum, Category, Report
 from flaskbb.management.models import Setting, SettingsGroup
 from flaskbb.management.models import Setting, SettingsGroup
@@ -398,7 +398,7 @@ def report_markread(report_id=None):
 
 
         for report in Report.query.filter(Report.id.in_(ids)).all():
         for report in Report.query.filter(Report.id.in_(ids)).all():
             report.zapped_by = current_user.id
             report.zapped_by = current_user.id
-            report.zapped = datetime.utcnow()
+            report.zapped = time_utcnow()
             report.save()
             report.save()
             data.append({
             data.append({
                 "id": report.id,
                 "id": report.id,
@@ -424,7 +424,7 @@ def report_markread(report_id=None):
             return redirect(url_for("management.reports"))
             return redirect(url_for("management.reports"))
 
 
         report.zapped_by = current_user.id
         report.zapped_by = current_user.id
-        report.zapped = datetime.utcnow()
+        report.zapped = time_utcnow()
         report.save()
         report.save()
         flash(_("Report %(id)s marked as read.", id=report.id), "success")
         flash(_("Report %(id)s marked as read.", id=report.id), "success")
         return redirect(url_for("management.reports"))
         return redirect(url_for("management.reports"))
@@ -434,7 +434,7 @@ def report_markread(report_id=None):
     report_list = []
     report_list = []
     for report in reports:
     for report in reports:
         report.zapped_by = current_user.id
         report.zapped_by = current_user.id
-        report.zapped = datetime.utcnow()
+        report.zapped = time_utcnow()
         report_list.append(report)
         report_list.append(report)
 
 
     db.session.add_all(report_list)
     db.session.add_all(report_list)

+ 6 - 7
flaskbb/message/models.py

@@ -8,12 +8,11 @@
     :copyright: (c) 2014 by the FlaskBB Team.
     :copyright: (c) 2014 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
-from datetime import datetime
-
 from sqlalchemy_utils import UUIDType
 from sqlalchemy_utils import UUIDType
 
 
 from flaskbb.extensions import db
 from flaskbb.extensions import db
-from flaskbb.utils.database import CRUDMixin
+from flaskbb.utils.helpers import time_utcnow
+from flaskbb.utils.database import CRUDMixin, UTCDateTime
 
 
 
 
 class Conversation(db.Model, CRUDMixin):
 class Conversation(db.Model, CRUDMixin):
@@ -25,7 +24,7 @@ class Conversation(db.Model, CRUDMixin):
     to_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
     to_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
     shared_id = db.Column(UUIDType, nullable=False)
     shared_id = db.Column(UUIDType, nullable=False)
     subject = db.Column(db.String(255))
     subject = db.Column(db.String(255))
-    date_created = db.Column(db.DateTime, default=datetime.utcnow())
+    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
     trash = db.Column(db.Boolean, nullable=False, default=False)
     trash = db.Column(db.Boolean, nullable=False, default=False)
     draft = db.Column(db.Boolean, nullable=False, default=False)
     draft = db.Column(db.Boolean, nullable=False, default=False)
     unread = db.Column(db.Boolean, nullable=False, default=True)
     unread = db.Column(db.Boolean, nullable=False, default=True)
@@ -63,7 +62,7 @@ class Conversation(db.Model, CRUDMixin):
         """
         """
         if message is not None:
         if message is not None:
             # create the conversation
             # create the conversation
-            self.date_created = datetime.utcnow()
+            self.date_created = time_utcnow()
             db.session.add(self)
             db.session.add(self)
             db.session.commit()
             db.session.commit()
 
 
@@ -86,7 +85,7 @@ class Message(db.Model, CRUDMixin):
     # the user who wrote the message
     # the user who wrote the message
     user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
     user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
     message = db.Column(db.Text, nullable=False)
     message = db.Column(db.Text, nullable=False)
-    date_created = db.Column(db.DateTime, default=datetime.utcnow())
+    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
 
 
     user = db.relationship("User", lazy="joined")
     user = db.relationship("User", lazy="joined")
 
 
@@ -98,7 +97,7 @@ class Message(db.Model, CRUDMixin):
         """
         """
         if conversation is not None:
         if conversation is not None:
             self.conversation_id = conversation.id
             self.conversation_id = conversation.id
-            self.date_created = datetime.utcnow()
+            self.date_created = time_utcnow()
 
 
         db.session.add(self)
         db.session.add(self)
         db.session.commit()
         db.session.commit()

+ 2 - 3
flaskbb/message/views.py

@@ -9,7 +9,6 @@
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
 import uuid
 import uuid
-from datetime import datetime
 
 
 from flask import Blueprint, redirect, request, url_for, flash, abort
 from flask import Blueprint, redirect, request, url_for, flash, abort
 from flask_login import login_required, current_user
 from flask_login import login_required, current_user
@@ -17,7 +16,7 @@ from flask_babelplus import gettext as _
 
 
 from flaskbb.extensions import db
 from flaskbb.extensions import db
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.settings import flaskbb_config
-from flaskbb.utils.helpers import render_template, format_quote
+from flaskbb.utils.helpers import render_template, format_quote, time_utcnow
 from flaskbb.message.forms import ConversationForm, MessageForm
 from flaskbb.message.forms import ConversationForm, MessageForm
 from flaskbb.message.models import Conversation, Message
 from flaskbb.message.models import Conversation, Message
 from flaskbb.user.models import User
 from flaskbb.user.models import User
@@ -228,7 +227,7 @@ def edit_conversation(conversation_id):
             # Move the message from ``Drafts`` to ``Sent``.
             # Move the message from ``Drafts`` to ``Sent``.
             conversation.draft = False
             conversation.draft = False
             conversation.to_user = to_user
             conversation.to_user = to_user
-            conversation.date_created = datetime.utcnow()
+            conversation.date_created = time_utcnow()
             conversation.save()
             conversation.save()
 
 
             flash(_("Message sent."), "success")
             flash(_("Message sent."), "success")

+ 8 - 8
flaskbb/user/models.py

@@ -9,7 +9,6 @@
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
 import os
 import os
-from datetime import datetime
 
 
 from werkzeug.security import generate_password_hash, check_password_hash
 from werkzeug.security import generate_password_hash, check_password_hash
 from flask import url_for
 from flask import url_for
@@ -18,8 +17,9 @@ from flask_login import UserMixin, AnonymousUserMixin
 from flaskbb._compat import max_integer
 from flaskbb._compat import max_integer
 from flaskbb.extensions import db, cache
 from flaskbb.extensions import db, cache
 from flaskbb.exceptions import AuthenticationError
 from flaskbb.exceptions import AuthenticationError
+from flaskbb.utils.helpers import time_utcnow
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.settings import flaskbb_config
-from flaskbb.utils.database import CRUDMixin
+from flaskbb.utils.database import CRUDMixin, UTCDateTime
 from flaskbb.forum.models import (Post, Topic, topictracker, TopicsRead,
 from flaskbb.forum.models import (Post, Topic, topictracker, TopicsRead,
                                   ForumsRead)
                                   ForumsRead)
 from flaskbb.message.models import Conversation
 from flaskbb.message.models import Conversation
@@ -82,9 +82,9 @@ class User(db.Model, UserMixin, CRUDMixin):
     username = db.Column(db.String(200), unique=True, nullable=False)
     username = db.Column(db.String(200), unique=True, nullable=False)
     email = db.Column(db.String(200), unique=True, nullable=False)
     email = db.Column(db.String(200), unique=True, nullable=False)
     _password = db.Column('password', db.String(120), nullable=False)
     _password = db.Column('password', db.String(120), nullable=False)
-    date_joined = db.Column(db.DateTime, default=datetime.utcnow())
-    lastseen = db.Column(db.DateTime, default=datetime.utcnow())
-    birthday = db.Column(db.DateTime)
+    date_joined = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
+    lastseen = db.Column(UTCDateTime(timezone=True), default=time_utcnow())
+    birthday = db.Column(UTCDateTime(timezone=True))
     gender = db.Column(db.String(10))
     gender = db.Column(db.String(10))
     website = db.Column(db.String(200))
     website = db.Column(db.String(200))
     location = db.Column(db.String(100))
     location = db.Column(db.String(100))
@@ -92,7 +92,7 @@ class User(db.Model, UserMixin, CRUDMixin):
     avatar = db.Column(db.String(200))
     avatar = db.Column(db.String(200))
     notes = db.Column(db.Text)
     notes = db.Column(db.Text)
 
 
-    last_failed_login = db.Column(db.DateTime)
+    last_failed_login = db.Column(UTCDateTime(timezone=True))
     login_attempts = db.Column(db.Integer, default=0)
     login_attempts = db.Column(db.Integer, default=0)
     activated = db.Column(db.Boolean, default=False)
     activated = db.Column(db.Boolean, default=False)
 
 
@@ -174,7 +174,7 @@ class User(db.Model, UserMixin, CRUDMixin):
     @property
     @property
     def days_registered(self):
     def days_registered(self):
         """Returns the amount of days the user is registered."""
         """Returns the amount of days the user is registered."""
-        days_registered = (datetime.utcnow() - self.date_joined).days
+        days_registered = (time_utcnow() - self.date_joined).days
         if not days_registered:
         if not days_registered:
             return 1
             return 1
         return days_registered
         return days_registered
@@ -247,7 +247,7 @@ class User(db.Model, UserMixin, CRUDMixin):
 
 
             # user exists, wrong password
             # user exists, wrong password
             user.login_attempts += 1
             user.login_attempts += 1
-            user.last_failed_login = datetime.utcnow()
+            user.last_failed_login = time_utcnow()
             user.save()
             user.save()
 
 
         # protection against account enumeration timing attacks
         # protection against account enumeration timing attacks

+ 24 - 0
flaskbb/utils/database.py

@@ -8,6 +8,8 @@
     :copyright: (c) 2015 by the FlaskBB Team.
     :copyright: (c) 2015 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
+import pytz
+
 from flaskbb.extensions import db
 from flaskbb.extensions import db
 
 
 
 
@@ -26,3 +28,25 @@ class CRUDMixin(object):
         db.session.delete(self)
         db.session.delete(self)
         db.session.commit()
         db.session.commit()
         return self
         return self
+
+
+class UTCDateTime(db.TypeDecorator):
+    impl = db.DateTime
+
+    def process_bind_param(self, value, dialect):
+        """Way into the database."""
+        if value is not None:
+            # store naive datetime for sqlite
+            if dialect.name == "sqlite":
+                return value.replace(tzinfo=None)
+
+            return value.astimezone(pytz.UTC)
+
+    def process_result_value(self, value, dialect):
+        """Way out of the database."""
+        # convert naive datetime to non naive datetime
+        if dialect.name == "sqlite" and value is not None:
+            return value.replace(tzinfo=pytz.UTC)
+
+        # other dialects are already non-naive
+        return value

+ 10 - 4
flaskbb/utils/helpers.py

@@ -15,6 +15,7 @@ import operator
 import struct
 import struct
 from io import BytesIO
 from io import BytesIO
 from datetime import datetime, timedelta
 from datetime import datetime, timedelta
+from pytz import UTC
 
 
 import requests
 import requests
 import unidecode
 import unidecode
@@ -203,7 +204,7 @@ def forum_is_unread(forum, forumsread, user):
     if not user.is_authenticated:
     if not user.is_authenticated:
         return False
         return False
 
 
-    read_cutoff = datetime.utcnow() - timedelta(
+    read_cutoff = time_utcnow() - timedelta(
         days=flaskbb_config["TRACKER_LENGTH"])
         days=flaskbb_config["TRACKER_LENGTH"])
 
 
     # disable tracker if TRACKER_LENGTH is set to 0
     # disable tracker if TRACKER_LENGTH is set to 0
@@ -250,7 +251,7 @@ def topic_is_unread(topic, topicsread, user, forumsread=None):
     if not user.is_authenticated:
     if not user.is_authenticated:
         return False
         return False
 
 
-    read_cutoff = datetime.utcnow() - timedelta(
+    read_cutoff = time_utcnow() - timedelta(
         days=flaskbb_config["TRACKER_LENGTH"])
         days=flaskbb_config["TRACKER_LENGTH"])
 
 
     # disable tracker if read_cutoff is set to 0
     # disable tracker if read_cutoff is set to 0
@@ -349,11 +350,16 @@ def is_online(user):
     return user.lastseen >= time_diff()
     return user.lastseen >= time_diff()
 
 
 
 
+def time_utcnow():
+    """Returns a timezone aware utc timestamp."""
+    return datetime.now(UTC)
+
+
 def time_diff():
 def time_diff():
     """Calculates the time difference between now and the ONLINE_LAST_MINUTES
     """Calculates the time difference between now and the ONLINE_LAST_MINUTES
     variable from the configuration.
     variable from the configuration.
     """
     """
-    now = datetime.utcnow()
+    now = time_utcnow()
     diff = now - timedelta(minutes=flaskbb_config['ONLINE_LAST_MINUTES'])
     diff = now - timedelta(minutes=flaskbb_config['ONLINE_LAST_MINUTES'])
     return diff
     return diff
 
 
@@ -386,7 +392,7 @@ def time_since(time):  # pragma: no cover
 
 
     :param time: A datetime object
     :param time: A datetime object
     """
     """
-    delta = time - datetime.utcnow()
+    delta = time - time_utcnow()
     return format_timedelta(delta, add_direction=True)
     return format_timedelta(delta, add_direction=True)
 
 
 
 

+ 0 - 1
tests/fixtures/user.py

@@ -1,4 +1,3 @@
-import datetime
 import pytest
 import pytest
 from flaskbb.user.models import User, Guest
 from flaskbb.user.models import User, Guest
 
 

+ 4 - 4
tests/unit/utils/test_helpers.py

@@ -2,7 +2,7 @@
 import datetime
 import datetime
 from flaskbb.utils.helpers import slugify, forum_is_unread, topic_is_unread, \
 from flaskbb.utils.helpers import slugify, forum_is_unread, topic_is_unread, \
     crop_title, render_markup, is_online, format_date, format_quote, \
     crop_title, render_markup, is_online, format_date, format_quote, \
-    get_image_info, check_image
+    get_image_info, check_image, time_utcnow
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.forum.models import Forum
 from flaskbb.forum.models import Forum
 
 
@@ -59,8 +59,8 @@ def test_topic_is_unread(guest, user, forum, topic, topicsread, forumsread):
     assert topic_is_unread(topic, topicsread=None, user=user, forumsread=forumsread)
     assert topic_is_unread(topic, topicsread=None, user=user, forumsread=forumsread)
 
 
     # lets mark the forum as read
     # lets mark the forum as read
-    forumsread.cleared = datetime.datetime.utcnow()
-    forumsread.last_read = datetime.datetime.utcnow()
+    forumsread.cleared = time_utcnow()
+    forumsread.last_read = time_utcnow()
     forumsread.save()
     forumsread.save()
     assert not topic_is_unread(topic, topicsread=None, user=user, forumsread=forumsread)
     assert not topic_is_unread(topic, topicsread=None, user=user, forumsread=forumsread)
 
 
@@ -69,7 +69,7 @@ def test_topic_is_unread(guest, user, forum, topic, topicsread, forumsread):
     assert not topic_is_unread(topic, None, user, None)
     assert not topic_is_unread(topic, None, user, None)
 
 
     # post is older than tracker length
     # post is older than tracker length
-    time_posted = datetime.datetime.utcnow() - datetime.timedelta(days=2)
+    time_posted = time_utcnow() - datetime.timedelta(days=2)
     flaskbb_config["TRACKER_LENGTH"] = 1
     flaskbb_config["TRACKER_LENGTH"] = 1
     topic.last_post.date_created = time_posted
     topic.last_post.date_created = time_posted
     topic.save()
     topic.save()