Call systemd SetTime directly

Internally inside phosphor-time-manager, the elapsed(uint64) dbus call
just forwards the request directly to systemd after static casting to
int64_t (signed).

bmcweb should just call systemd directly, for several reasons.

phosphor-timesyncd might block on other calls, given it's a single
threaded blocking design, due to bugs like #264.  Calling systemd
directly means that calls that don't require phosphor networkd won't be
blocked.

Calling systemd directly allows bmcweb to drop some code that parses a
date as int64_t, then converts it to uint64_t to fulfill the phosphor
datetime interface.  We can now keep int64_t all the way through.

Calling systemd directly allows bmcweb to give a more specific error
code in the case there NTP is enabled, registering a
PropertyValueConflict error, instead of a 500 InternalError.

Tested:
Patching DateTime property with NTP enabled returns 400,
PropertyValueConflict
```
curl -vvvv  -k --user "root:0penBmc" -H "Content-Type: application/json" -X PATCH -d '{"DateTime":"2020-12-15T15:40:52+00:00"}' https://192.168.7.2/redfish/v1/Managers/bmc
```

Disabling NTP using the following command:
```
curl -vvvv  -k --user "root:0penBmc" -H "Content-Type: application/json" -X PATCH -d '{"NTP":{"ProtocolEnabled":false}}' https://192.168.7.2/redfish/v1/Managers/bmc/NetworkProtocol
```

Allows the prior command to succeed.

[1] https://github.com/openbmc/phosphor-time-manager/blob/5ce9ac0e56440312997b25771507585905e8b360/bmc_epoch.cpp#L126

Change-Id: I6fbb6f63e17de8ab847ca5ed4eadc2bd313586d2
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index 527076f..26abec0 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -1857,8 +1857,37 @@
     });
 }
 
-inline void setDateTime(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
-                        std::string datetime)
+inline void
+    afterSetDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                     const boost::system::error_code& ec,
+                     const sdbusplus::message_t& msg)
+{
+    if (ec)
+    {
+        BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
+                         ec);
+        const sd_bus_error* dbusError = msg.get_error();
+        if (dbusError != nullptr)
+        {
+            std::string_view errorName(dbusError->name);
+            if (errorName ==
+                "org.freedesktop.timedate1.AutomaticTimeSyncEnabled")
+            {
+                BMCWEB_LOG_DEBUG("Setting conflict");
+                messages::propertyValueConflict(
+                    asyncResp->res, "DateTime",
+                    "Managers/NetworkProtocol/NTPProcotolEnabled");
+                return;
+            }
+        }
+        messages::internalError(asyncResp->res);
+        return;
+    }
+    asyncResp->res.result(boost::beast::http::status::no_content);
+}
+
+inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                        const std::string& datetime)
 {
     BMCWEB_LOG_DEBUG("Set date time: {}", datetime);
 
@@ -1870,22 +1899,17 @@
                                            "DateTime");
         return;
     }
-    sdbusplus::asio::setProperty(
-        *crow::connections::systemBus, "xyz.openbmc_project.Time.Manager",
-        "/xyz/openbmc_project/time/bmc", "xyz.openbmc_project.Time.EpochTime",
-        "Elapsed", us->count(),
-        [asyncResp{std::move(asyncResp)},
-         datetime{std::move(datetime)}](const boost::system::error_code& ec) {
-        if (ec)
-        {
-            BMCWEB_LOG_DEBUG("Failed to set elapsed time. "
-                             "DBUS response error {}",
-                             ec);
-            messages::internalError(asyncResp->res);
-            return;
-        }
-        asyncResp->res.jsonValue["DateTime"] = datetime;
-    });
+    // Set the absolute datetime
+    bool relative = false;
+    bool interactive = false;
+    crow::connections::systemBus->async_method_call(
+        [asyncResp](const boost::system::error_code& ec,
+                    const sdbusplus::message_t& msg) {
+        afterSetDateTime(asyncResp, ec, msg);
+    },
+        "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
+        "org.freedesktop.timedate1", "SetTime", us->count(), relative,
+        interactive);
 }
 
 inline void
@@ -2259,7 +2283,7 @@
         }
         if (datetime)
         {
-            setDateTime(asyncResp, std::move(*datetime));
+            setDateTime(asyncResp, *datetime);
         }
     });
 }