@@ -3562,8 +3562,12 @@ let get_ntp_servers_status ~__context ~self:_ =
35623562 else
35633563 []
35643564
3565+ (* Prevent concurrent time/timezeone operations from interleaving. *)
3566+ let time_m = Mutex. create ()
3567+
35653568let set_timezone ~__context ~self ~value =
35663569 try
3570+ with_lock time_m @@ fun () ->
35673571 let _ =
35683572 Helpers. call_script ! Xapi_globs. timedatectl [" set-timezone" ; value]
35693573 in
@@ -3588,3 +3592,27 @@ let get_ntp_synchronized ~__context ~self:_ =
35883592 r
35893593 | Error msg ->
35903594 Helpers. internal_error " %s" msg
3595+
3596+ let set_servertime ~__context ~self ~value =
3597+ let f = Helpers. call_script ! Xapi_globs. timedatectl in
3598+ with_lock time_m @@ fun () ->
3599+ let tz = Db.Host. get_timezone ~__context ~self in
3600+ let not_utc = tz <> " UTC" in
3601+ try
3602+ (* The [value] stores only a naive date/time and a fixed timezone offset.
3603+ Convert it to UTC to avoid ambiguities caused by additional timezone
3604+ details, such as Daylight Saving Time (DST) rules or historical changes. *)
3605+ match Date. to_utc value |> Option. map Date. to_ptime with
3606+ | Some t ->
3607+ let (y, mon, d), ((h, min, s), _) = Ptime. to_date_time t in
3608+ let naive_in_utc =
3609+ Printf. sprintf " %04i-%02i-%02i %02i:%02i:%02i" y mon d h min s
3610+ in
3611+ if not_utc then (f [" set-timezone" ; " UTC" ] : string ) |> ignore ;
3612+ (f [" set-time" ; naive_in_utc] : string ) |> ignore ;
3613+ if not_utc then (f [" set-timezone" ; tz] : string ) |> ignore ;
3614+ debug " %s: %s" __FUNCTION__ (f [" status" ])
3615+ | None ->
3616+ raise (Invalid_argument " Missing timezone offset in value" )
3617+ with e ->
3618+ Helpers. internal_error " %s: %s" __FUNCTION__ (ExnHelper. string_of_exn e)
0 commit comments