diff --git a/homeassistant/components/utility_meter/__init__.py b/homeassistant/components/utility_meter/__init__.py
index d64b40ed60bf5ec483485bfb20ba07a6b13d20cc..c91bbcb7e578d1fcace7401b0bb7159c3fd2fc1f 100644
--- a/homeassistant/components/utility_meter/__init__.py
+++ b/homeassistant/components/utility_meter/__init__.py
@@ -65,6 +65,16 @@ def period_or_cron(config):
     return config
 
 
+def max_28_days(config):
+    """Check that time period does not include more then 28 days."""
+    if config.days >= 28:
+        raise vol.Invalid(
+            "Unsupported offset of more then 28 days, please use a cron pattern."
+        )
+
+    return config
+
+
 METER_CONFIG_SCHEMA = vol.Schema(
     vol.All(
         {
@@ -72,7 +82,7 @@ METER_CONFIG_SCHEMA = vol.Schema(
             vol.Optional(CONF_NAME): cv.string,
             vol.Optional(CONF_METER_TYPE): vol.In(METER_TYPES),
             vol.Optional(CONF_METER_OFFSET, default=DEFAULT_OFFSET): vol.All(
-                cv.time_period, cv.positive_timedelta
+                cv.time_period, cv.positive_timedelta, max_28_days
             ),
             vol.Optional(CONF_METER_NET_CONSUMPTION, default=False): cv.boolean,
             vol.Optional(CONF_TARIFFS, default=[]): vol.All(
diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py
index 29ea478f0b3202c0cfef95eb72048da4a8eec4e3..ec553cce58adf610ccf9e3568bf873daaf4d2ee6 100644
--- a/homeassistant/components/utility_meter/sensor.py
+++ b/homeassistant/components/utility_meter/sensor.py
@@ -1,7 +1,6 @@
 """Utility meter from sensors providing raw data."""
-from datetime import date, datetime, timedelta
-import decimal
-from decimal import Decimal, DecimalException
+from datetime import datetime
+from decimal import Decimal, DecimalException, InvalidOperation
 import logging
 
 from croniter import croniter
@@ -29,7 +28,6 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
 from homeassistant.helpers.event import (
     async_track_point_in_time,
     async_track_state_change_event,
-    async_track_time_change,
 )
 from homeassistant.helpers.restore_state import RestoreEntity
 import homeassistant.util.dt as dt_util
@@ -59,6 +57,17 @@ from .const import (
     YEARLY,
 )
 
+PERIOD2CRON = {
+    QUARTER_HOURLY: "{minute}/15 * * * *",
+    HOURLY: "{minute} * * * *",
+    DAILY: "{minute} {hour} * * *",
+    WEEKLY: "{minute} {hour} * * {day}",
+    MONTHLY: "{minute} {hour} {day} * *",
+    BIMONTHLY: "{minute} {hour} {day} */2 *",
+    QUARTERLY: "{minute} {hour} {day} */3 *",
+    YEARLY: "{minute} {hour} {day} 1/12 *",
+}
+
 _LOGGER = logging.getLogger(__name__)
 
 ATTR_SOURCE_ID = "source"
@@ -152,8 +161,16 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity):
             self._name = f"{source_entity} meter"
         self._unit_of_measurement = None
         self._period = meter_type
-        self._period_offset = meter_offset
-        self._cron_pattern = cron_pattern
+        if meter_type is not None:
+            # For backwards compatibility reasons we convert the period and offset into a cron pattern
+            self._cron_pattern = PERIOD2CRON[meter_type].format(
+                minute=meter_offset.seconds % 3600 // 60,
+                hour=meter_offset.seconds // 3600,
+                day=meter_offset.days + 1,
+            )
+            _LOGGER.debug("CRON pattern: %s", self._cron_pattern)
+        else:
+            self._cron_pattern = cron_pattern
         self._sensor_net_consumption = net_consumption
         self._tariff = tariff
         self._tariff_entity = tariff_entity
@@ -233,39 +250,12 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity):
 
     async def _async_reset_meter(self, event):
         """Determine cycle - Helper function for larger than daily cycles."""
-        now = dt_util.now().date()
         if self._cron_pattern is not None:
             async_track_point_in_time(
                 self.hass,
                 self._async_reset_meter,
                 croniter(self._cron_pattern, dt_util.now()).get_next(datetime),
             )
-        elif (
-            self._period == WEEKLY
-            and now != now - timedelta(days=now.weekday()) + self._period_offset
-        ):
-            return
-        elif (
-            self._period == MONTHLY
-            and now != date(now.year, now.month, 1) + self._period_offset
-        ):
-            return
-        elif (
-            self._period == BIMONTHLY
-            and now
-            != date(now.year, (((now.month - 1) // 2) * 2 + 1), 1) + self._period_offset
-        ):
-            return
-        elif (
-            self._period == QUARTERLY
-            and now
-            != date(now.year, (((now.month - 1) // 3) * 3 + 1), 1) + self._period_offset
-        ):
-            return
-        elif (
-            self._period == YEARLY and now != date(now.year, 1, 1) + self._period_offset
-        ):
-            return
         await self.async_reset_meter(self._tariff_entity)
 
     async def async_reset_meter(self, entity_id):
@@ -294,30 +284,6 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity):
                 self._async_reset_meter,
                 croniter(self._cron_pattern, dt_util.now()).get_next(datetime),
             )
-        elif self._period == QUARTER_HOURLY:
-            for quarter in range(4):
-                async_track_time_change(
-                    self.hass,
-                    self._async_reset_meter,
-                    minute=(quarter * 15)
-                    + self._period_offset.seconds % (15 * 60) // 60,
-                    second=self._period_offset.seconds % 60,
-                )
-        elif self._period == HOURLY:
-            async_track_time_change(
-                self.hass,
-                self._async_reset_meter,
-                minute=self._period_offset.seconds // 60,
-                second=self._period_offset.seconds % 60,
-            )
-        elif self._period in [DAILY, WEEKLY, MONTHLY, BIMONTHLY, QUARTERLY, YEARLY]:
-            async_track_time_change(
-                self.hass,
-                self._async_reset_meter,
-                hour=self._period_offset.seconds // 3600,
-                minute=self._period_offset.seconds % 3600 // 60,
-                second=self._period_offset.seconds % 3600 % 60,
-            )
 
         async_dispatcher_connect(self.hass, SIGNAL_RESET_METER, self.async_reset_meter)
 
@@ -325,7 +291,7 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity):
         if state:
             try:
                 self._state = Decimal(state.state)
-            except decimal.InvalidOperation:
+            except InvalidOperation:
                 _LOGGER.error(
                     "Could not restore state <%s>. Resetting utility_meter.%s",
                     state.state,
diff --git a/tests/components/utility_meter/test_sensor.py b/tests/components/utility_meter/test_sensor.py
index 91b03f7a1bb31a15a18038c2dbd459d8ce3b16ff..a41ddcfa9fce6f22b4bf63b554502d16b6e8ad11 100644
--- a/tests/components/utility_meter/test_sensor.py
+++ b/tests/components/utility_meter/test_sensor.py
@@ -627,7 +627,14 @@ async def test_no_reset_yearly_offset(hass, legacy_patchable_time):
     """Test yearly reset of meter."""
     await _test_self_reset(
         hass,
-        gen_config("yearly", timedelta(31)),
-        "2018-01-30T23:59:00.000000+00:00",
+        gen_config("yearly", timedelta(27)),
+        "2018-04-29T23:59:00.000000+00:00",
         expect_reset=False,
     )
+
+
+async def test_bad_offset(hass, legacy_patchable_time):
+    """Test bad offset of meter."""
+    assert not await async_setup_component(
+        hass, DOMAIN, gen_config("monthly", timedelta(days=31))
+    )