Created clockoffset endpoint and persisted per tenant.
diff --git a/api/src/main/java/io/mifos/rhythm/api/v1/client/RhythmManager.java b/api/src/main/java/io/mifos/rhythm/api/v1/client/RhythmManager.java
index 4b10d4f..a4f0981 100644
--- a/api/src/main/java/io/mifos/rhythm/api/v1/client/RhythmManager.java
+++ b/api/src/main/java/io/mifos/rhythm/api/v1/client/RhythmManager.java
@@ -17,6 +17,7 @@
 
 import io.mifos.core.api.util.CustomFeignClientsConfiguration;
 import io.mifos.rhythm.api.v1.domain.Beat;
+import io.mifos.rhythm.api.v1.domain.ClockOffset;
 import org.springframework.cloud.netflix.feign.FeignClient;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -31,6 +32,21 @@
 @SuppressWarnings("unused")
 @FeignClient(value="rhythm-v1", path="/rhythm/v1", configuration = CustomFeignClientsConfiguration.class)
 public interface RhythmManager {
+  @RequestMapping(
+      value = "/clockoffset",
+      method = RequestMethod.PUT,
+      produces = MediaType.APPLICATION_JSON_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE
+  )
+  void setClockOffset(ClockOffset clockOffset);
+
+  @RequestMapping(
+      value = "/clockoffset",
+      method = RequestMethod.GET,
+      produces = MediaType.APPLICATION_JSON_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE
+  )
+  ClockOffset getClockOffset();
 
   @RequestMapping(
           value = "/applications/{applicationidentifier}",
diff --git a/api/src/main/java/io/mifos/rhythm/api/v1/domain/ClockOffset.java b/api/src/main/java/io/mifos/rhythm/api/v1/domain/ClockOffset.java
new file mode 100644
index 0000000..fbb8132
--- /dev/null
+++ b/api/src/main/java/io/mifos/rhythm/api/v1/domain/ClockOffset.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.api.v1.domain;
+
+import org.hibernate.validator.constraints.Range;
+
+import java.util.Objects;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings({"WeakerAccess", "unused"})
+public class ClockOffset {
+  @Range(min = 0, max = 23)
+  private Integer hours;
+
+  @Range(min = 0, max = 59)
+  private Integer minutes;
+
+  @Range(min = 0, max = 59)
+  private Integer seconds;
+
+  public ClockOffset() {
+    this.hours = 0;
+    this.minutes = 0;
+    this.seconds = 0;
+  }
+
+  public ClockOffset(Integer hours, Integer minutes) {
+    this.hours = hours;
+    this.minutes = minutes;
+    this.seconds = 0;
+  }
+
+  public ClockOffset(Integer hours, Integer minutes, Integer seconds) {
+    this.hours = hours;
+    this.minutes = minutes;
+    this.seconds = seconds;
+  }
+
+  public Integer getHours() {
+    return hours;
+  }
+
+  public void setHours(Integer hours) {
+    this.hours = hours;
+  }
+
+  public Integer getMinutes() {
+    return minutes;
+  }
+
+  public void setMinutes(Integer minutes) {
+    this.minutes = minutes;
+  }
+
+  public Integer getSeconds() {
+    return seconds;
+  }
+
+  public void setSeconds(Integer seconds) {
+    this.seconds = seconds;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+    ClockOffset that = (ClockOffset) o;
+    return Objects.equals(hours, that.hours) &&
+        Objects.equals(minutes, that.minutes) &&
+        Objects.equals(seconds, that.seconds);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(hours, minutes, seconds);
+  }
+
+  @Override
+  public String toString() {
+    return "ClockOffset{" +
+        "hours=" + hours +
+        ", minutes=" + minutes +
+        ", seconds=" + seconds +
+        '}';
+  }
+}
diff --git a/api/src/main/java/io/mifos/rhythm/api/v1/events/EventConstants.java b/api/src/main/java/io/mifos/rhythm/api/v1/events/EventConstants.java
index 878999c..9f84439 100644
--- a/api/src/main/java/io/mifos/rhythm/api/v1/events/EventConstants.java
+++ b/api/src/main/java/io/mifos/rhythm/api/v1/events/EventConstants.java
@@ -27,8 +27,10 @@
   String POST_BEAT = "post-beat";
   String DELETE_APPLICATION = "delete-application";
   String DELETE_BEAT = "delete-beat";
+  String PUT_CLOCKOFFSET = "put-clockoffset";
   String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
   String SELECTOR_POST_BEAT = SELECTOR_NAME + " = '" + POST_BEAT + "'";
   String SELECTOR_DELETE_APPLICATION = SELECTOR_NAME + " = '" + DELETE_APPLICATION + "'";
   String SELECTOR_DELETE_BEAT = SELECTOR_NAME + " = '" + DELETE_BEAT + "'";
+  String SELECTOR_PUT_CLOCKOFFSET = SELECTOR_NAME + " = '" + PUT_CLOCKOFFSET + "'";
 }
diff --git a/api/src/test/java/io/mifos/rhythm/api/v1/domain/ClockOffsetTest.java b/api/src/test/java/io/mifos/rhythm/api/v1/domain/ClockOffsetTest.java
new file mode 100644
index 0000000..62bdc52
--- /dev/null
+++ b/api/src/test/java/io/mifos/rhythm/api/v1/domain/ClockOffsetTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.api.v1.domain;
+
+import io.mifos.core.test.domain.ValidationTest;
+import io.mifos.core.test.domain.ValidationTestCase;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * @author Myrle Krantz
+ */
+public class ClockOffsetTest extends ValidationTest<ClockOffset> {
+  public ClockOffsetTest(final ValidationTestCase<ClockOffset> testCase) {
+    super(testCase);
+  }
+
+  @Override
+  protected ClockOffset createValidTestSubject() {
+    return new ClockOffset();
+  }
+
+  @Parameterized.Parameters
+  public static Collection testCases() {
+    final Collection<ValidationTestCase> ret = new ArrayList<>();
+    ret.add(new ValidationTestCase<ClockOffset>("basicCase")
+        .adjustment(x -> {})
+        .valid(true));
+    ret.add(new ValidationTestCase<ClockOffset>("everythingMidRange")
+        .adjustment(x -> {x.setHours(12); x.setMinutes(30); x.setSeconds(30);})
+        .valid(true));
+    ret.add(new ValidationTestCase<ClockOffset>("negativeHours")
+        .adjustment(x -> x.setHours(-1))
+        .valid(false));
+    ret.add(new ValidationTestCase<ClockOffset>("outOfDayHours")
+        .adjustment(x -> x.setHours(24))
+        .valid(false));
+    ret.add(new ValidationTestCase<ClockOffset>("negativeMinutes")
+        .adjustment(x -> x.setMinutes(-1))
+        .valid(false));
+    ret.add(new ValidationTestCase<ClockOffset>("outOfRangeMinutes")
+        .adjustment(x -> x.setMinutes(60))
+        .valid(false));
+    ret.add(new ValidationTestCase<ClockOffset>("negativeSeconds")
+        .adjustment(x -> x.setMinutes(-1))
+        .valid(false));
+    ret.add(new ValidationTestCase<ClockOffset>("outOfRangeSeconds")
+        .adjustment(x -> x.setMinutes(60))
+        .valid(false));
+    return ret;
+  }
+}
\ No newline at end of file
diff --git a/component-test/src/main/java/io/mifos/rhythm/TestBeats.java b/component-test/src/main/java/io/mifos/rhythm/TestBeats.java
index 7535700..b3890a9 100644
--- a/component-test/src/main/java/io/mifos/rhythm/TestBeats.java
+++ b/component-test/src/main/java/io/mifos/rhythm/TestBeats.java
@@ -17,6 +17,7 @@
 
 import io.mifos.core.api.util.NotFoundException;
 import io.mifos.rhythm.api.v1.domain.Beat;
+import io.mifos.rhythm.api.v1.domain.ClockOffset;
 import io.mifos.rhythm.api.v1.events.BeatEvent;
 import io.mifos.rhythm.api.v1.events.EventConstants;
 import io.mifos.rhythm.service.internal.repository.BeatEntity;
@@ -28,6 +29,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 
 import javax.transaction.Transactional;
+import java.time.Clock;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.temporal.ChronoUnit;
@@ -131,6 +133,23 @@
   }
 
   @Test
+  public void shouldChangeTheTenantClockOffset() throws InterruptedException {
+    final ClockOffset initialClockOffset = this.testSubject.getClockOffset();
+    Assert.assertEquals(Integer.valueOf(0), initialClockOffset.getHours());
+    Assert.assertEquals(Integer.valueOf(0), initialClockOffset.getMinutes());
+    Assert.assertEquals(Integer.valueOf(0), initialClockOffset.getSeconds());
+
+    final LocalDateTime now = LocalDateTime.now(Clock.systemUTC());
+    final ClockOffset offsetToNow = new ClockOffset(now.getHour(), now.getMinute(), now.getSecond());
+    this.testSubject.setClockOffset(offsetToNow);
+
+    Assert.assertTrue(this.eventRecorder.wait(EventConstants.PUT_CLOCKOFFSET, offsetToNow));
+
+    final ClockOffset changedClockOffset = this.testSubject.getClockOffset();
+    Assert.assertEquals(offsetToNow, changedClockOffset);
+  }
+
+  @Test
   public void shouldBeatForMissingDays() throws InterruptedException {
     final String applicationIdentifier = "funnybusiness-v6";
     final String beatIdentifier = "fiddlebeat";
diff --git a/component-test/src/main/java/io/mifos/rhythm/listener/ClockOffsetEventListener.java b/component-test/src/main/java/io/mifos/rhythm/listener/ClockOffsetEventListener.java
new file mode 100644
index 0000000..890df79
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/rhythm/listener/ClockOffsetEventListener.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.listener;
+
+import io.mifos.core.lang.config.TenantHeaderFilter;
+import io.mifos.core.test.listener.EventRecorder;
+import io.mifos.rhythm.api.v1.domain.ClockOffset;
+import io.mifos.rhythm.api.v1.events.EventConstants;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jms.annotation.JmsListener;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@Component
+public class ClockOffsetEventListener {
+  private final EventRecorder eventRecorder;
+
+  @Autowired
+  public ClockOffsetEventListener(@SuppressWarnings("SpringJavaAutowiringInspection") final EventRecorder eventRecorder) {
+    super();
+    this.eventRecorder = eventRecorder;
+  }
+
+  @JmsListener(
+      subscription = EventConstants.DESTINATION,
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_PUT_CLOCKOFFSET
+  )
+  public void onChangeClockOffset(
+      @Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+      final String payload) {
+    this.eventRecorder.event(tenant, EventConstants.PUT_CLOCKOFFSET, payload, ClockOffset.class);
+  }
+}
diff --git a/service/src/main/java/io/mifos/rhythm/service/internal/command/ChangeClockOffsetCommand.java b/service/src/main/java/io/mifos/rhythm/service/internal/command/ChangeClockOffsetCommand.java
new file mode 100644
index 0000000..36104bd
--- /dev/null
+++ b/service/src/main/java/io/mifos/rhythm/service/internal/command/ChangeClockOffsetCommand.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.service.internal.command;
+
+import io.mifos.rhythm.api.v1.domain.ClockOffset;
+
+/**
+ * @author Myrle Krantz
+ */
+public class ChangeClockOffsetCommand {
+  private final String tenantIdentifier;
+
+  private final ClockOffset instance;
+
+  public ChangeClockOffsetCommand(
+      final String tenantIdentifier,
+      final ClockOffset instance) {
+    this.tenantIdentifier = tenantIdentifier;
+    this.instance = instance;
+  }
+
+  public String getTenantIdentifier() {
+    return tenantIdentifier;
+  }
+
+  public ClockOffset getInstance() {
+    return instance;
+  }
+
+  @Override
+  public String toString() {
+    return "ChangeClockOffsetCommand{" +
+        "tenantIdentifier='" + tenantIdentifier + '\'' +
+        ", instance=" + instance +
+        '}';
+  }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/rhythm/service/internal/command/handler/ClockOffsetCommandHandler.java b/service/src/main/java/io/mifos/rhythm/service/internal/command/handler/ClockOffsetCommandHandler.java
new file mode 100644
index 0000000..19d55d7
--- /dev/null
+++ b/service/src/main/java/io/mifos/rhythm/service/internal/command/handler/ClockOffsetCommandHandler.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.service.internal.command.handler;
+
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.CommandLogLevel;
+import io.mifos.rhythm.api.v1.events.EventConstants;
+import io.mifos.rhythm.service.ServiceConstants;
+import io.mifos.rhythm.service.internal.command.ChangeClockOffsetCommand;
+import io.mifos.rhythm.service.internal.mapper.ClockOffsetMapper;
+import io.mifos.rhythm.service.internal.repository.ClockOffsetEntity;
+import io.mifos.rhythm.service.internal.repository.ClockOffsetRepository;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+import java.util.Optional;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@Aggregate
+public class ClockOffsetCommandHandler {
+  private final ClockOffsetRepository clockOffsetRepository;
+  private final EventHelper eventHelper;
+  private final Logger logger;
+
+  @Autowired
+  public ClockOffsetCommandHandler(
+      final ClockOffsetRepository clockOffsetRepository,
+      final EventHelper eventHelper,
+      @Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger) {
+    super();
+    this.clockOffsetRepository = clockOffsetRepository;
+    this.eventHelper = eventHelper;
+    this.logger = logger;
+  }
+
+  @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.NONE)
+  public void process(final ChangeClockOffsetCommand changeClockOffsetCommand) {
+
+    final Optional<ClockOffsetEntity> existingClockOffset =
+        clockOffsetRepository.findByTenantIdentifier(changeClockOffsetCommand.getTenantIdentifier());
+
+    final ClockOffsetEntity clockOffsetEntity = ClockOffsetMapper.map(
+        changeClockOffsetCommand.getTenantIdentifier(),
+        changeClockOffsetCommand.getInstance(),
+        existingClockOffset);
+
+    clockOffsetRepository.save(clockOffsetEntity);
+
+    logger.info("Sending change clock offset event.");
+    eventHelper.sendEvent(
+        EventConstants.PUT_CLOCKOFFSET,
+        changeClockOffsetCommand.getTenantIdentifier(),
+        changeClockOffsetCommand.getInstance());
+  }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/rhythm/service/internal/mapper/ClockOffsetMapper.java b/service/src/main/java/io/mifos/rhythm/service/internal/mapper/ClockOffsetMapper.java
new file mode 100644
index 0000000..2188fda
--- /dev/null
+++ b/service/src/main/java/io/mifos/rhythm/service/internal/mapper/ClockOffsetMapper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.service.internal.mapper;
+
+import io.mifos.rhythm.api.v1.domain.ClockOffset;
+import io.mifos.rhythm.service.internal.repository.ClockOffsetEntity;
+
+import java.util.Optional;
+
+/**
+ * @author Myrle Krantz
+ */
+public interface ClockOffsetMapper {
+  static ClockOffset map(final ClockOffsetEntity entity) {
+    final ClockOffset ret = new ClockOffset();
+    ret.setHours(entity.getHours());
+    ret.setMinutes(entity.getMinutes());
+    ret.setSeconds(entity.getSeconds());
+    return ret;
+  }
+
+  @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
+  static ClockOffsetEntity map(
+      final String tenantIdentifier,
+      final ClockOffset instance,
+      final Optional<ClockOffsetEntity> existingClockOffset) {
+    final ClockOffsetEntity ret = new ClockOffsetEntity();
+    existingClockOffset.ifPresent(x -> ret.setId(x.getId()));
+    ret.setTenantIdentifier(tenantIdentifier);
+    ret.setHours(instance.getHours());
+    ret.setMinutes(instance.getMinutes());
+    ret.setSeconds(instance.getSeconds());
+    return ret;
+  }
+}
diff --git a/service/src/main/java/io/mifos/rhythm/service/internal/repository/ClockOffsetEntity.java b/service/src/main/java/io/mifos/rhythm/service/internal/repository/ClockOffsetEntity.java
new file mode 100644
index 0000000..e105a95
--- /dev/null
+++ b/service/src/main/java/io/mifos/rhythm/service/internal/repository/ClockOffsetEntity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.service.internal.repository;
+
+import javax.persistence.*;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings({"unused", "WeakerAccess"})
+@Entity
+@Table(name = "khepri_clockoffsets")
+public class ClockOffsetEntity {
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id")
+  private Long id;
+
+  @Column(name = "tenant_identifier", nullable = false)
+  private String tenantIdentifier;
+
+  @Column(name = "hours", nullable = false)
+  private Integer hours;
+
+  @Column(name = "minutes", nullable = false)
+  private Integer minutes;
+
+  @Column(name = "seconds", nullable = false)
+  private Integer seconds;
+
+  public Long getId() {
+    return id;
+  }
+
+  public void setId(Long id) {
+    this.id = id;
+  }
+
+  public String getTenantIdentifier() {
+    return tenantIdentifier;
+  }
+
+  public void setTenantIdentifier(String tenantIdentifier) {
+    this.tenantIdentifier = tenantIdentifier;
+  }
+
+  public Integer getHours() {
+    return hours;
+  }
+
+  public void setHours(Integer hours) {
+    this.hours = hours;
+  }
+
+  public Integer getMinutes() {
+    return minutes;
+  }
+
+  public void setMinutes(Integer minutes) {
+    this.minutes = minutes;
+  }
+
+  public Integer getSeconds() {
+    return seconds;
+  }
+
+  public void setSeconds(Integer seconds) {
+    this.seconds = seconds;
+  }
+}
diff --git a/service/src/main/java/io/mifos/rhythm/service/internal/repository/ClockOffsetRepository.java b/service/src/main/java/io/mifos/rhythm/service/internal/repository/ClockOffsetRepository.java
new file mode 100644
index 0000000..3005457
--- /dev/null
+++ b/service/src/main/java/io/mifos/rhythm/service/internal/repository/ClockOffsetRepository.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface ClockOffsetRepository extends JpaRepository<ClockOffsetEntity, Long> {
+  Optional<ClockOffsetEntity> findByTenantIdentifier(String tenantIdentifier);
+}
diff --git a/service/src/main/java/io/mifos/rhythm/service/internal/service/ClockOffsetService.java b/service/src/main/java/io/mifos/rhythm/service/internal/service/ClockOffsetService.java
new file mode 100644
index 0000000..07c17e0
--- /dev/null
+++ b/service/src/main/java/io/mifos/rhythm/service/internal/service/ClockOffsetService.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.service.internal.service;
+
+import io.mifos.rhythm.api.v1.domain.ClockOffset;
+import io.mifos.rhythm.service.internal.mapper.ClockOffsetMapper;
+import io.mifos.rhythm.service.internal.repository.ClockOffsetRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author Myrle Krantz
+ */
+@Service
+public class ClockOffsetService {
+  final private ClockOffsetRepository clockOffsetRepository;
+
+  @Autowired
+  public ClockOffsetService(final ClockOffsetRepository clockOffsetRepository) {
+    this.clockOffsetRepository = clockOffsetRepository;
+  }
+
+  public ClockOffset findByTenant(final String tenantIdentifier) {
+    return clockOffsetRepository.findByTenantIdentifier(tenantIdentifier)
+        .map(ClockOffsetMapper::map)
+        .orElseGet(ClockOffset::new);
+  }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/rhythm/service/rest/ClockOffsetRestController.java b/service/src/main/java/io/mifos/rhythm/service/rest/ClockOffsetRestController.java
new file mode 100644
index 0000000..a788d28
--- /dev/null
+++ b/service/src/main/java/io/mifos/rhythm/service/rest/ClockOffsetRestController.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.rhythm.service.rest;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.rhythm.api.v1.domain.ClockOffset;
+import io.mifos.rhythm.service.internal.command.ChangeClockOffsetCommand;
+import io.mifos.rhythm.service.internal.service.ClockOffsetService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+import static io.mifos.core.lang.config.TenantHeaderFilter.TENANT_HEADER;
+
+/**
+ * @author Myrle Krantz
+ */
+@RestController
+@RequestMapping("/clockoffset")
+public class ClockOffsetRestController {
+  private final CommandGateway commandGateway;
+  private final ClockOffsetService clockOffsetService;
+
+  @Autowired
+  public ClockOffsetRestController(
+      final CommandGateway commandGateway,
+      final ClockOffsetService clockOffsetService) {
+    super();
+    this.commandGateway = commandGateway;
+    this.clockOffsetService = clockOffsetService;
+  }
+
+  @Permittable(value = AcceptedTokenType.SYSTEM)
+  @RequestMapping(
+      method = RequestMethod.GET,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  public
+  @ResponseBody
+  ResponseEntity<ClockOffset> getClockOffset(@RequestHeader(TENANT_HEADER) final String tenantIdentifier) {
+    return ResponseEntity.ok(this.clockOffsetService.findByTenant(tenantIdentifier));
+  }
+
+  @Permittable(value = AcceptedTokenType.SYSTEM)
+  @RequestMapping(
+      method = RequestMethod.PUT,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  public
+  @ResponseBody
+  ResponseEntity<Void> setClockOffset(
+      @RequestHeader(TENANT_HEADER) final String tenantIdentifier,
+      @RequestBody @Valid final ClockOffset instance) throws InterruptedException {
+    this.commandGateway.process(new ChangeClockOffsetCommand(tenantIdentifier, instance));
+    return ResponseEntity.accepted().build();
+  }
+}
diff --git a/service/src/main/resources/db/migrations/mariadb/V2__tenant_clock_offset.sql b/service/src/main/resources/db/migrations/mariadb/V2__tenant_clock_offset.sql
new file mode 100644
index 0000000..c6b3662
--- /dev/null
+++ b/service/src/main/resources/db/migrations/mariadb/V2__tenant_clock_offset.sql
@@ -0,0 +1,25 @@
+--
+-- Copyright 2017 Kuelap, Inc.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--    http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+CREATE TABLE khepri_clockoffsets (
+  id BIGINT NOT NULL AUTO_INCREMENT,
+  tenant_identifier        VARCHAR(32)  NOT NULL,
+  hours                    INT          NOT NULL,
+  minutes                  INT          NOT NULL,
+  seconds                  INT          NOT NULL,
+  CONSTRAINT khepri_clockoffsets_uq UNIQUE (tenant_identifier),
+  CONSTRAINT khepri_clockoffsets_pk PRIMARY KEY (id)
+);
\ No newline at end of file
diff --git a/shared.gradle b/shared.gradle
index dc7dd71..0170643 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -65,7 +65,9 @@
         xml = 'XML_STYLE'
         yml = 'SCRIPT_STYLE'
         yaml = 'SCRIPT_STYLE'
+        uxf = 'XML_STYLE'
     }
     ext.year = Calendar.getInstance().get(Calendar.YEAR)
-    ext.name = 'The Mifos Initiative'
+    ext.name = 'Kuelap, Inc'
+    skipExistingHeaders true
 }