」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 如何使用 Go 在伺服器端處理時區並同步您的軟體

如何使用 Go 在伺服器端處理時區並同步您的軟體

發佈於2024-11-03
瀏覽:635

当你的应用大规模启动时,用户的增量就会增加。很可能发生的情况是,用户的位置不仅在同一区域,还可能在具有不同时区的另一个区域。因此作为后端开发人员,与处理时区差异相关的事情是非常需要考虑的。

我最近遇到了一个涉及时区的问题。老实说,处理日期和时间是人类必须处理的最复杂的领域之一。这是我学习如何在服务器端正确处理日期和时间的机会。

在这篇文章中,我将分享我作为后端开发人员如何处理服务器端时区差异的经验。也许如果有人愿意纠正并提供对我有价值的额外意见。

关于时区

时区是全世界使用的标准时分系统,用于组织和标准化时间的测量。这一概念的出现是为了响应全球时间协调的需求,特别是随着通信和运输技术的发展。

时区的基本原理是将地球划分为24个时区。每个时区通常与其相邻时区相差一小时。时区的主要参考是格林威治标准时间 (GMT) 或协调世界时 (UTC),位于穿过英国格林威治的零度经线。

How to Handle Time Zones and Sync Your Software on the server side using Go
来自维基共享资源的 Hellerick 插图

一个小例子是,当雅加达的时钟显示中午 12:00 时,纽约的时间显示 00:00 或午夜。这意味着当雅加达人正在享用午餐时,纽约人才刚刚开始新的一天。从这里您当然可以想象在构建应用程序时正确处理时区的重要性。

服务器端的时区处理

看完上面的解释后,现在我们将讨论当我们的服务器应用程序收到来自访问我们的 API 来处理其时区的客户端的请求时可以执行的操作。

在本文中,我将讨论在服务器端处理时区的几种方法。这里我将使用Golang(Go)语言的代码示例。 Golang 有一个用于处理与时间相关的数据的时间包,它被认为是相当完整的。以下是我们将讨论的一些要点:

  • 如何将日期保存到数据库
  • 用户当地时间的转换
  • 测试和验证

如何将日期保存到数据库

我们要讨论的第一件事是我们将在数据库中保存哪些时间,例如我们有一个进行闪购的电子商务应用程序,我们的应用程序已经在国际范围内。

当用户在美国或印度尼西亚处理购买交易时,用户会将不同的当地时间发送到服务器。问题是,我们的数据库会按照用户当地时间存储时间数据吗?如果答案是肯定的,那么当我们想要检索数据或者例如管理员想要进行数据处理时,这可能是一个复杂的问题,哪个用户最早进行交易。

为了克服这个问题,最佳实践是将交易时间存储在 UTC(协调世界时)时区,这是时钟和时间设置的主要时间标准。这里是将时间应用到 UTC。

package main

import (
    "fmt"
    "time"
)

func main() {

    now := time.Now()
    fmt.Printf("Local time: %s\n", now)

    nowInUTC := now.UTC()
    fmt.Printf("UTC time: %s\n", nowInUTC)

}

我们看看上面代码的含义。

首先,在 now := time.Now() 代码行中,该行使用 time 包中的 Now() 函数根据系统本地时区获取当前时间。结果存储在当前变量中。

然后,在 nowInUTC := now.UTC() 行中,我们使用 UTC() 方法将本地时间(现在)转换为 UTC 时间。结果存储在一个新的变量nowInUTC中,这个时间可以存储在服务器上,希望开发者能够避免由于不同时区的各个地区的服务器和用户之间的时区差异而可能出现的歧义和错误。

如果我们运行上面的代码,结果如下:

How to Handle Time Zones and Sync Your Software on the server side using Go

但这并不总是您应该使用的最佳解决方案。在某些用例中,您可能需要记住一些要点,其中之一是我们的用户真的来自不同时区吗?如果不可能,也许以 UTC 形式存储时间会增加代码的复杂性。

将时间更改为用户区域设置

在上面的讨论中,我们同意将用户时间数据存储在一个位置,即 UTC。现在用户如何根据自己的位置查看准确的时间。上面讨论的一个例子是我们拥有的电子商务应用程序上的限时抢购,用户还想知道有关哪个用户进行了第一笔交易的信息。所以此时,将我们存储在数据库中的时间转换为用户本地时间是我们不应该忽视的另一件重要的事情。

我采取的方法是服务器端总是要求客户端发送用户端的时区。这可以在请求端完成,客户端发送带有关键时区的标头并具有用户的时区值。例如,印度尼西亚有3个时区划分,分别是WIT(9)、WITA(8)、WIB(7)。其中每个区域有1小时的时差。如果之前在我们的服务器上我们存储的 UTC 时间为 00.00,那么在 WIT 端它为 09.00,然后在 WITA 端它为 08.00,WIB 为 07.00。

下面是处理上述情况的示例代码:

package main

import (
    "fmt"
    "time"
)

func ParseTimezoneFromString(tz string) *time.Location {

    if len(tz) > 0 {

        t, err := time.Parse("2006 -07:00", fmt.Sprintf("2007 %s", tz))

        if err != nil {

            panic(err)

        } else {

            return t.Location()
        }
    }

    return time.Now().Location()
}

func main() {

    timeServerInUTC := "2024-08-04 00:00:00"
    nowInUTC, err := time.Parse("2006-01-02 15:04:05", timeServerInUTC)
    if err != nil {
        panic(err)
    }

    fmt.Printf("UTC time: %s\n", nowInUTC)

    witLocation := ParseTimezoneFromString(" 09:00")

    nowInWIT := nowInUTC.In(witLocation)
    fmt.Printf("WIT time: %s\n", nowInWIT)

    witaLocation := ParseTimezoneFromString(" 08:00")

    nowInWITA := nowInUTC.In(witaLocation)
    fmt.Printf("WITA time: %s\n", nowInWITA)

    wibLocation := ParseTimezoneFromString(" 07:00")

    nowInWIB := nowInUTC.In(wibLocation)
    fmt.Printf("WIB time: %s\n", nowInWIB)

}

归功于 dikac 创建此函数 ParseTimezoneFromString

我们来理解一下上面代码的含义:

首先,我们创建一个函数 ParseTimezoneFromString,该函数用于根据参数 tz 或给定用户位置的时区查找时间位置。如果字符串值 tz 有效,我们将使用 time.Parse 函数转换字符串的时区,将字符串转换为时间对象,然后从该对象中提取位置(时区)。我们还处理如果字符串为空或解析失败,函数返回系统的本地时区。

func ParseTimezoneFromString(tz string) *time.Location {

    if len(tz) > 0 {

        t, err := time.Parse("2006 -07:00", fmt.Sprintf("2007 %s", tz))

        if err != nil {

            panic(err)

        } else {

            return t.Location()
        }
    }

    return time.Now().Location()
}

接下来我们还定义以下字符串格式的时间数据:

timeServerInUTC := "2024-08-04 00:00:00"

nowInUTC, err := time.Parse("2006-01-02 15:04:05", timeServerInUTC)
if err != nil {
    panic(err)
}

您可以将其视为我们从服务器获取的计时数据。并将其解析为时间对象。

接下来,我们尝试根据我们之前根据定义的字符串参数创建的 ParseTimezoneFromString 函数来查找用户的准确位置。需要注意的是,这个字符串参数是客户端通过传入请求发送的时区标头的值的含义。

我们可以使用从 ParseTimezoneFromString 函数获取的位置将从服务器获取的时间转换或转移到用户的本地时间。我们可以使用 In 函数来完成此操作,该函数也包含在 time 包中,我们可以在以下代码片段中看到:

nowInWIT := nowInUTC.In(witLocation)
nowInWITA := nowInUTC.In(witaLocation)
nowInWIB := nowInUTC.In(wibLocation)

如果我们运行它,我们将获得与我们定义的时区位置相对应的时间。

How to Handle Time Zones and Sync Your Software on the server side using Go

测试和验证

最后一点同样重要,即测试和验证。当开发过程经常导致开发人员犯下意想不到的错误时,测试和验证总是很重要。

在上面第 2 点的讨论中,ParseTimezoneFromString 函数在处理时区方面非常重要。重复测试和验证对于使我们的应用程序获得满足我们期望的结果非常重要。

测试时,建议使用单元测试,在最小的单元上进行测试,并可以添加多个场景。场景越多,处理这些时间差异的可能性就越小。

结论

处理时区对于后端开发人员来说确实很棘手。然而,重要的是要记住,我们克服的每一项具有挑战性的任务都有助于我们的成长和技能提高。正确管理时区不仅仅是技术上的需要,它还能确保调度的准确性,并为不同地区的应用程序用户提供流畅的体验。

本文中分享的有关以 UTC 格式存储时间、转换为用户本地时间以及实现强大的转换函数的要点是解决这一复杂问题的起点。然而,我承认所讨论的方法可能存在缺点或需要改进的地方。这就是为什么开发者社区的额外意见和建议非常宝贵。

我真诚地希望本文中提供的见解和代码示例能够在您将来在项目中遇到与时区相关的挑战时对您有所帮助。请记住,我们的目标是创建能够为用户无缝工作的应用程序,无论他们的地理位置如何。

让我们在下面的评论部分继续讨论。我很想听听您处理时区的经验、您遇到的任何挑战,或者您发现有效的替代方法。您的见解对于我和其他面临类似问题的读者来说非常有价值。

感谢您的阅读,希望本文对您的开发之旅有所帮助。让我们一起不断学习、共同进步! ?

阅读参考文献

  • 时区
  • 什么是时区?
  • 如何处理时区并使您的软件与国际客户同步
  • 在网络开发中处理时区
  • 在 Go 中使用日期和时间:处理时区和格式
版本聲明 本文轉載於:https://dev.to/tentanganak/how-to-handle-time-zones-and-sync-your-software-on-the-server-side-using-go-16ip?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 查找當前執行JavaScript的腳本元素方法
    查找當前執行JavaScript的腳本元素方法
    如何引用當前執行腳本的腳本元素在某些方案中理解問題在某些方案中,開發人員可能需要將其他腳本動態加載其他腳本。但是,如果Head Element尚未完全渲染,則使用document.getElementsbytagname('head')[0] .appendChild(v)的常規方...
    程式設計 發佈於2025-05-15
  • Go web應用何時關閉數據庫連接?
    Go web應用何時關閉數據庫連接?
    在GO Web Applications中管理數據庫連接很少,考慮以下簡化的web應用程序代碼:出現的問題:何時應在DB連接上調用Close()方法? ,該特定方案將自動關閉程序時,該程序將在EXITS EXITS EXITS出現時自動關閉。但是,其他考慮因素可能保證手動處理。 選項1:隱式關閉終...
    程式設計 發佈於2025-05-15
  • 為什麼我在Silverlight Linq查詢中獲得“無法找到查詢模式的實現”錯誤?
    為什麼我在Silverlight Linq查詢中獲得“無法找到查詢模式的實現”錯誤?
    查詢模式實現缺失:解決“無法找到”錯誤在Silverlight應用程序中,嘗試使用LINQ建立LINQ連接以錯誤而實現的數據庫”,無法找到查詢模式的實現。”當省略LINQ名稱空間或查詢類型缺少IEnumerable 實現時,通常會發生此錯誤。 解決問題來驗證該類型的質量是至關重要的。在此特定實例...
    程式設計 發佈於2025-05-15
  • 在C#中如何高效重複字符串字符用於縮進?
    在C#中如何高效重複字符串字符用於縮進?
    在基於項目的深度下固定字符串時,重複一個字符串以進行凹痕,很方便有效地有一種有效的方法來返回字符串重複指定的次數的字符串。使用指定的次數。 constructor 這將返回字符串“ -----”。 字符串凹痕= new String(' - ',depth); console.W...
    程式設計 發佈於2025-05-15
  • Java的Map.Entry和SimpleEntry如何簡化鍵值對管理?
    Java的Map.Entry和SimpleEntry如何簡化鍵值對管理?
    A Comprehensive Collection for Value Pairs: Introducing Java's Map.Entry and SimpleEntryIn Java, when defining a collection where each element com...
    程式設計 發佈於2025-05-15
  • 我可以將加密從McRypt遷移到OpenSSL,並使用OpenSSL遷移MCRYPT加密數據?
    我可以將加密從McRypt遷移到OpenSSL,並使用OpenSSL遷移MCRYPT加密數據?
    將我的加密庫從mcrypt升級到openssl 問題:是否可以將我的加密庫從McRypt升級到OpenSSL?如果是這樣,如何? 答案:是的,可以將您的Encryption庫從McRypt升級到OpenSSL。 可以使用openssl。 附加說明: [openssl_decrypt()函數要求...
    程式設計 發佈於2025-05-15
  • CSS強類型語言解析
    CSS強類型語言解析
    您可以通过其强度或弱输入的方式对编程语言进行分类的方式之一。在这里,“键入”意味着是否在编译时已知变量。一个例子是一个场景,将整数(1)添加到包含整数(“ 1”)的字符串: result = 1 "1";包含整数的字符串可能是由带有许多运动部件的复杂逻辑套件无意间生成的。它也可以是故意从单个真理...
    程式設計 發佈於2025-05-15
  • 如何在php中使用捲髮發送原始帖子請求?
    如何在php中使用捲髮發送原始帖子請求?
    如何使用php 創建請求來發送原始帖子請求,開始使用curl_init()開始初始化curl session。然後,配置以下選項: curlopt_url:請求 [要發送的原始數據指定內容類型,為原始的帖子請求指定身體的內容類型很重要。在這種情況下,它是文本/平原。要執行此操作,請使用包含以下標頭...
    程式設計 發佈於2025-05-15
  • C++中如何將獨占指針作為函數或構造函數參數傳遞?
    C++中如何將獨占指針作為函數或構造函數參數傳遞?
    在構造函數和函數中將唯一的指數管理為參數 unique pointers( unique_ptr [2啟示。通過值: base(std :: simelor_ptr n) :next(std :: move(n)){} 此方法將唯一指針的所有權轉移到函數/對象。指針的內容被移至功能中,在操作...
    程式設計 發佈於2025-05-15
  • 版本5.6.5之前,使用current_timestamp與時間戳列的current_timestamp與時間戳列有什麼限制?
    版本5.6.5之前,使用current_timestamp與時間戳列的current_timestamp與時間戳列有什麼限制?
    在時間戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源於遺留實現的關注,這些限制需要對當前的_timestamp功能進行特定的實現。 創建表`foo`( `Productid` int(10)unsigned not ...
    程式設計 發佈於2025-05-15
  • 大批
    大批
    [2 數組是對象,因此它們在JS中也具有方法。 切片(開始):在新數組中提取部分數組,而無需突變原始數組。 令ARR = ['a','b','c','d','e']; // USECASE:提取直到索引作...
    程式設計 發佈於2025-05-15
  • 為什麼儘管有效代碼,為什麼在PHP中捕獲輸入?
    為什麼儘管有效代碼,為什麼在PHP中捕獲輸入?
    在php ;?>" method="post">The intention is to capture the input from the text box and display it when the submit button is clicked.但是,輸出...
    程式設計 發佈於2025-05-15
  • 在Java中如何為PNG文件添加坐標軸和標籤?
    在Java中如何為PNG文件添加坐標軸和標籤?
    如何用java 在現有png映像中添加軸和標籤的axes和labels如何註釋png文件可能具有挑戰性。與其嘗試可能導致錯誤和不一致的修改,不如建議在圖表創建過程中集成註釋。 使用JFReechArt import java.awt.color; 導入java.awt.eventqueue; 導...
    程式設計 發佈於2025-05-15
  • FastAPI自定義404頁面創建指南
    FastAPI自定義404頁面創建指南
    response = await call_next(request) if response.status_code == 404: return RedirectResponse("https://fastapi.tiangolo.com") else: ...
    程式設計 發佈於2025-05-15
  • Python中嵌套函數與閉包的區別是什麼
    Python中嵌套函數與閉包的區別是什麼
    嵌套函數與python 在python中的嵌套函數不被考慮閉合,因為它們不符合以下要求:不訪問局部範圍scliables to incling scliables在封裝範圍外執行範圍的局部範圍。 make_printer(msg): DEF打印機(): 打印(味精) ...
    程式設計 發佈於2025-05-15

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3