pq:日期/时间字段值超出范围:“22/02/2022”

cag*_*ngs 0 postgresql go google-cloud-sql

我有这样的疑问:

    l.loyaltycard_number, l.recipt_no, 
    l.totaltrans_amount, l.amount_paid, 
    l.reward_points, l.redeemed_points,
    cashier FROM loyalty l
    JOIN warehouses w
    ON l.machine_ip = w.machine_ip
    WHERE l.machine_name = $1 
    AND redeemed_points != $2
    AND trasaction_time BETWEEN $3 AND  $4
    ORDER BY trasaction_time DESC;
Run Code Online (Sandbox Code Playgroud)

我有用于 transaction_time 的 HTML 日期选择器,格式为 dd/mm/yyyy。

每当我选择第一个数字大于 12 (22/02/2022) 的日期范围时。我收到上述错误。我怀疑是格式问题。

我在文档中找到了如何将 postgresql 日期样式设置为 DMY。这样做之后,我得到了同样的错误。

但是,当我在 Postgres cli 中运行相同的查询时,如下所示:

SELECT w.machine_name, l.trasaction_time,
        l.loyaltycard_number, l.recipt_no, 
        l.totaltrans_amount, l.amount_paid, 
        l.reward_points, l.redeemed_points,
        cashier FROM loyalty l
        JOIN warehouses w
        ON l.machine_ip = w.machine_ip
        WHERE l.machine_name = 'HERMSERVER'
        AND redeemed_points != 0
        AND trasaction_time BETWEEN '14/11/21' AND  '22/02/22'
        ORDER BY trasaction_time DESC;
Run Code Online (Sandbox Code Playgroud)

我得到了预期的结果。我不知道我做错了什么。我想知道如何使数据库将日期选择器中的日期视为 dd/mm/yyyy 而不是 mm/dd/yyyy。我正在使用谷歌cloudsql Postgres

这是从日期选择器获取数据的处理程序的代码

err := r.ParseForm()

    if err != nil {
        app.clientError(w, http.StatusBadRequest)
    }

    startDate := r.PostForm.Get("startDate")
    endDate := r.PostForm.Get("endDate")
    outlet := r.PostForm.Get("outlet")
    reportType := r.PostForm.Get("repoType")

    if reportType == "0" {
        rReport, err := app.models.Reports.GetRedeemedReport(startDate, endDate, outlet, reportType)
        if err != nil {
            app.serverError(w, err)
            return
        }

        app.render(w, r, "tranxreport.page.tmpl", &templateData{
            Reports: rReport,
        })
    } else if reportType == "1" {
        rReport, err := app.models.Reports.GetAllReport(startDate, endDate, outlet)
        if err != nil {
            app.serverError(w, err)
            return
        }

        app.render(w, r, "tranxreport.page.tmpl", &templateData{
            Reports: rReport,
        })
    } else {
        app.render(w, r, "tranxreport.page.tmpl", &templateData{})
    }
Run Code Online (Sandbox Code Playgroud)

Bri*_*its 5

根据评论,虽然应该可以更改,DateStyle但存在一些问题:

  • 该命令更改当前会话SET datestyle的样式。由于该包使用连接池,因此用途有限。SQL
  • 可以使用“postgresql.conf 配置文件中的 DateStyle 参数,或服务器上的 PGDATESTYLE 环境变量”,但这在 Postgres 作为托管服务提供时可能不可用。请注意,进行此更改还意味着如果未设置该参数,您的软件将失败(当移动到新服务器时,这很容易完成)。

一个相对简单的解决方案是编辑您的查询以使用TO_DATE例如:

BETWEEN TO_DATE($3,'DD/MM/YYYY') AND TO_DATE($4,'DD/MM/YYYY')
Run Code Online (Sandbox Code Playgroud)

然而,尽管这可行,但它会使您的数据库代码依赖于发送到 API 的数据格式。这意味着,例如,引入新的日期选择器可能会以一种很容易被错过的方式破坏您的代码(无论哪种方式,月初的测试都可以)。

更好的解决方案可能是在 API 中使用标准日期格式(例如 ISO 8601)和/或将日期作为time.Time. 然而,由于时区、夏令时等原因,这确实需要小心。

  • 这仅掩盖了真正的问题 - 使用本地化字符串而不是正确键入的查询参数。它也只能偶然工作 - 不能保证该字符串位于“DD/MM/YY”中。别介意重新引入千年虫问题。那是1945年的“45”还是2045年?如果这是出生日期怎么办?还是保险到期日?这并不是吹毛求疵 - 2020 年 1 月,IT 领域的重大新闻是 [Lloyd's](https://www.theregister.com/2020/01/02/lloyds_outage/) 网上银行和英国的 DVLA [因使用两位数日期](https://www.theregister.com/2020/01/13/y2k_dvla/) (3认同)