Postgresql 将不正确的时区输入数据库
我已经创建了一个表,该表的列带有带时区的dateTime。 在my model.py中: 我在heroku pg:psql上使用Postgresql 将不正确的时区输入数据库,postgresql,datetime,heroku,flask,Postgresql,Datetime,Heroku,Flask,我已经创建了一个表,该表的列带有带时区的dateTime。 在my model.py中: 我在heroku pg:psql上使用db.create_all()创建了表,结果如下: DATABASE=> \d messages Table "public.messages" Column | Type | Modifiers
db.create_all()
创建了表,结果如下:
DATABASE=> \d messages
Table "public.messages"
Column | Type | Modifiers
-----------+-----------------------+-----------------------------------------------------------
msg_id | integer | not null default nextval('messages_msg_id_seq'::regclass)
fullName | character varying(60) |
message | character varying |
email | character varying |
visitorId | character varying(10) |
done | boolean |
pub_date | time with time zone |
无论我使用的是什么时区/日期时间,时区似乎都会被打孔+00
,即UTC
4 | ciasto | testing | | 9IQVW1K6W | f | 15:48:31.784704+00
为什么会这样
我正在使用下面的路由函数传递时间,该函数应该将正确的dtWithZone
从下面传递到postgreSQL的表消息pub_date
@app.route('/newmsg', methods=['GET', 'POST'])
def newmsg():
form = _appforms.MessagingForm()
if form.validate_on_submit():
name = request.form['fullName']
ip = request.access_route[0] # gives ip address of the visitor
unique_visitor_id = request.cookies.get("unique_visitor")
data = _utils.getJsonFromURL("http://ip-api.com/json/{}".format(ip))
tz = "Asia/Kolkata"
if data["status"] == "success":
tz = data["timezone"]
flash("Your IP is {} and you are visiting this site from {} timezone.".format(ip, tz))
dtWithZone = datetime.datetime.now(pytz.timezone(tz))
msg = Messages(name, request.form['email'], request.form['message'], unique_visitor_id, dtWithZone)
_db.session.add(msg)
_db.session.commit()
msg = "Thank you, {}".format(name)
return render_template('thankyou.html', form=form, msg=msg)
return render_template('newMessage.html', form=form, title=" | Messaging", msg="Write your message")
但是,这在我的本地计算机上正常工作,查看表条目,我可以看到:
8 | tester | local teasing | | NV33A1L66 | f | 21:09:24.804903+05:30
我自己想起来了
,因为PostgreSQL时区感知,如果我们在时区上打上datetime,它会将其转换为PostgreSQL本地时区,所以在heroku上它被设置为UTC,所以它总是转换为UTC格式,所以我将列发布日期
转换为db.String(24)
并将日期/时间/与时区一起保存为字符串。它工作得很好。
更新消息:
首先定义具有接受带时区的datetime列的表:
src/model.py
from sqlalchemy import MetaData
from sqlalchemy import create_engine
from sqlalchemy import DateTime
db = SQLAlchemy(app)
class Messages(db.Model):
__tablename__ = 'messages'
msgId = db.Column('msg_id', db.Integer, primary_key=True)
fullName = db.Column(db.String(60))
message = db.Column(db.String)
email = db.Column(db.String, unique=True)
visitorId = db.Column(db.String(10))
done = db.Column(db.Boolean)
pub_date = db.Column(DateTime(timezone=True))
然后从python终端:从src.model import db运行;db.create_all()
这将在postgresql中创建具有正确列类型/名称的表。
然后使用下面的函数连接到带有用户时区的postgresSQL:
def insertIntoTable(dtWithZone, tableName, columValues):
db_uri = "postgresql://localhost/messages"
engine = create_engine(db_uri, connect_args={"options": "-c timezone={}".format(dtWithZone.timetz().tzinfo.zone)})
meta = MetaData(engine, reflect=True)
table = meta.tables[tableName]
ins = table.insert().values(**columValues)
conn = engine.connect()
conn.execute(ins)
conn.close()
就这样
现在,通过路由功能,我做了以下更改:
@app.route('/newmsg', methods=['GET', 'POST'])
def newmsg():
form = _appforms.MessagingForm()
# if form.validate_on_submit():
if request.method == "POST":
ip = request.access_route[0]
data = _utils.getJsonFromURL("http://ip-api.com/json/{}".format(ip))
tz = "Pacific/America"
if data["status"] == "success":
tz = data.get("timezone")
dtWithZone = datetime.datetime.now(pytz.timezone(tz))
name = request.form.get('fullName', "")
columValues = {
'pub_date' : dtWithZone,
'fullName' : name,
'visitorId': request.cookies.get("unique_visitor", ""),
'message' : request.form.get('message', ""),
'email' : request.form.get('email', "")
}
insertIntoTable(dtWithZone, 'messages', columValues)
msg = "Thank you, {}".format(name)
return render_template('thankyou.html', form=form, msg=msg)
return render_template('newMessage.html', form=form, title=" | Messaging", msg="Write your message")
非常适合(y)所以这里有一个关于时区的简短教程。要查看postgresql内部tz数据库中的时区,请运行以下查询:
select * from pg_timezone_names ;
(edited list)
name | abbrev | utc_offset | is_dst
----------------------------------+--------+------------+--------
America/Denver | MDT | -06:00:00 | t
America/Phoenix | MST | -07:00:00 | f
America/New_York | EDT | -04:00:00 | t
America/Chicago | CDT | -05:00:00 | t
America/Los_Angeles | PDT | -07:00:00 | t
下面是设置tz和插入时间戳的示例:
create table tztest (ts timestamptz, tz text);
set timezone="America/New_York";
insert into tztest values ('2017-01-10 12:00:00','America/New_York');
set timezone='America/Chicago';
insert into tztest values ('2017-01-10 12:00:00','America/Chicago');
set timezone='America/Denver';
insert into tztest values ('2017-01-10 12:00:00','America/Denver');
set timezone='America/Phoenix';
insert into tztest values ('2017-01-10 12:00:00','America/Phoenix');
set timezone='America/Los_Angeles';
insert into tztest values ('2017-01-10 12:00:00','America/Los_Angeles')
select * from tztest ;
ts | tz
------------------------+---------------------
2017-01-10 09:00:00-08 | America/New_York
2017-01-10 10:00:00-08 | America/Chicago
2017-01-10 11:00:00-08 | America/Denver
2017-01-10 11:00:00-08 | America/Phoenix
2017-01-10 12:00:00-08 | America/Los_Angeles
请注意,虽然洛杉矶被列为具有-07:00:00偏移量,但它不是夏季,所以现在1月份的日期为-08:00:00
要查看实际存储的时间戳,请将时区设置为UTC:
set timezone='UTC';
select * from tztest ;
ts | tz
------------------------+---------------------
2017-01-10 17:00:00+00 | America/New_York
2017-01-10 18:00:00+00 | America/Chicago
2017-01-10 19:00:00+00 | America/Denver
2017-01-10 19:00:00+00 | America/Phoenix
2017-01-10 20:00:00+00 | America/Los_Angeles
不是MySQL。删除标记。您还可以为每个连接设置时区,这将覆盖postgresql的内部时区。你也可以用“在时区tznamehere”来说明它所在的时区。处理文本中的日期/时间戳是一个很好的方法,因为它会改变时区偏移,如夏令时等。您的意思是说,对于每个连接,我执行一个查询
将时区设置为“用户的时区”代码>?你也可以做一些事情,比如改变用户、改变数据库等,让这些事情保持不变。注意,将用户的时区存储在某个地方也是很有帮助的。只是让db做时区工作,并知道它来自哪里。pg内部总是以utc的形式存储时间戳,不用担心,我用:db.Column(DateTime(timezone=True))
任何时候都可以!时区数学很奇怪,所以如果可能的话,我总是让db来处理这个问题。有另一个列来存储时区并没有什么坏处,所以我在我的项目中添加了一个新列来存储用户时区。
set timezone='UTC';
select * from tztest ;
ts | tz
------------------------+---------------------
2017-01-10 17:00:00+00 | America/New_York
2017-01-10 18:00:00+00 | America/Chicago
2017-01-10 19:00:00+00 | America/Denver
2017-01-10 19:00:00+00 | America/Phoenix
2017-01-10 20:00:00+00 | America/Los_Angeles