@Override
	public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
		super.onDataReceived(device, data);

		if (data.size() != 9 && data.size() != 11) {
			onInvalidDataReceived(device, data);
			return;
		}

		final boolean crcPresent = data.size() == 11;
		if (crcPresent) {
			final int actualCrc = CRC16.MCRF4XX(data.getValue(), 0, 9);
			final int expectedCrc = data.getIntValue(Data.FORMAT_UINT16_LE, 9);
			if (actualCrc != expectedCrc) {
				onContinuousGlucoseMonitorSessionStartTimeReceivedWithCrcError(device, data);
				return;
			}
		}

		final Calendar calendar = DateTimeDataCallback.readDateTime(data, 0);
		final Integer timeZoneOffset = TimeZoneDataCallback.readTimeZone(data, 7); // [minutes]
		final DSTOffsetCallback.DSTOffset dstOffset = DSTOffsetDataCallback.readDSTOffset(data, 8);

		if (calendar == null || timeZoneOffset == null || dstOffset == null) {
			onInvalidDataReceived(device, data);
			return;
		}

		final TimeZone timeZone = new TimeZone() {
			@Override
			public int getOffset(final int era, final int year, final int month, final int day, final int dayOfWeek, final int milliseconds) {
				return (timeZoneOffset + dstOffset.offset) * 60000; // convert minutes to milliseconds
			}

			@Override
			public void setRawOffset(final int offsetMillis) {
				throw new UnsupportedOperationException("Can't set raw offset for this TimeZone");
			}

			@Override
			public int getRawOffset() {
				return timeZoneOffset * 60000;
			}

			@Override
			public boolean useDaylightTime() {
				return true;
			}

			@Override
			public boolean inDaylightTime(final Date date) {
				// Use of DST is dependent on the input data only
				return dstOffset.offset > 0;
			}

			@Override
			public int getDSTSavings() {
				return dstOffset.offset * 60000;
			}

			// TODO add TimeZone ID
//			@Override
//			public String getID() {
//				return super.getID();
//			}
		};

		calendar.setTimeZone(timeZone);

		onContinuousGlucoseMonitorSessionStartTimeReceived(device, calendar, crcPresent);
	}
@Test
	public void onContinuousGlucoseMonitorSessionStartTimeReceived_noYear() {
		final Data data = new Data(new byte[] {(byte) 0, 0, 4, 24, 13, 8, 24, 8, 2 });
		callback.onDataReceived(null, data);
		assertTrue(success);
		assertFalse(verified);
		assertFalse(result.isSet(Calendar.YEAR));
		assertEquals(Calendar.APRIL, result.get(Calendar.MONTH));
		assertEquals(24, result.get(Calendar.DATE));
		assertEquals(13, result.get(Calendar.HOUR_OF_DAY));
		assertEquals(8, result.get(Calendar.MINUTE));
		assertEquals(24, result.get(Calendar.SECOND));
		assertEquals(8 * 60000, result.get(Calendar.ZONE_OFFSET));
		assertEquals(2 * 15 * 60000, result.get(Calendar.DST_OFFSET));
	}