docs: public byte[] getData(byte[] dst, int offset)
  	{
  		final int end = Math.min(data.length, dst.length - offset) / 3 * 3;
  		for (int i = 0; i < end; ++i)
  			dst[offset + i] = (byte) data[i];
  		return dst;
  	}
  
  	/* (non-Javadoc)
  	 * @see tuwien.auto.calimero.dptxlator.DPTXlator#getSubTypes()
  	 */
  	public Map getSubTypes()
  	{
  		return types;
  	}
  
  	/**
  	 * @return the subtypes of the time translator type
  	 * @see DPTXlator#getSubTypesStatic()
  	 */
  	protected static Map getSubTypesStatic()
  	{
  		return types;
  	}
  
  	private String fromDPT(int index)
  	{
  		if (sdf != null)
  			synchronized (DPTXlatorTime.class) {
  				return sdf.format(new Date(fromDPTMillis(index)));
  			}
  		final int i = index * 3;
  		// dow, hh:mm:ss
  		final int h = data[i + HOUR] & 0x1F;
  		final int m = data[i + MINUTE];
  		final int s = data[i + SECOND];
  		return DAYS[data[i + DOW] >> 5] + ", " + align(h) + h + ':' + align(m) + m + ':'
  			+ align(s) + s;
  	}
  
  	private long fromDPTMillis(int index)
  	{
  		synchronized (DPTXlatorTime.class) {
  			getCalendar().clear();
  			final int i = index * 3;
  			final int dow = data[i] >> 5 & 0x7;
  			if (dow > 0)
  				c.set(Calendar.DAY_OF_WEEK, dow == 7 ? 1 : dow + 1);
  			c.set(Calendar.HOUR_OF_DAY, data[i + HOUR] & 0x1F);
  			c.set(Calendar.MINUTE, data[i + MINUTE]);
  			c.set(Calendar.SECOND, data[i + SECOND]);
  			long ms = 0;
  			try {
  				ms = c.getTimeInMillis();
  			}
  			catch (final IllegalArgumentException e) {
  				DPTXlator.logger.error("from DPT in milliseconds not possible");
  			}
  			return ms;
  		}
  	}
  
  	protected void toDPT(String value, short[] dst, int index) throws KNXFormatException
  	{
  		if (sdf != null)
  			synchronized (DPTXlatorTime.class) {
  				toDPT(parse(value), dst, index);
  				return;
  			}
  		final StringTokenizer t = new StringTokenizer(value, ": ,");
  		final int maxTokens = 4;
  		final String[] tokens = new String[maxTokens];
  		// extract tokens
  		int count = 0;
  		for (; count < maxTokens && t.hasMoreTokens(); ++count)
  			tokens[count] = t.nextToken();
  		// we allow day of week to be omitted in value
  		if (count < 3)
  			throw logThrow(LogLevel.WARN, "invalid time " + value, null, value);
  		// on 4 tokens, day of week is included
  		final int dow = count == 4 ? getDOW(tokens[0]) : 0;
  		try {
  			final int s = Short.parseShort(tokens[--count]);
  			final int m = Short.parseShort(tokens[--count]);
  			final int h = Short.parseShort(tokens[--count]);
  			set(dow, h, m, s, dst, index);
  		}
  		catch (final KNXIllegalArgumentException e) {
  			throw logThrow(LogLevel.WARN, "invalid time " + value, e.getMessage(), value);
  		}
  		catch (final NumberFormatException e) {
  			throw logThrow(LogLevel.WARN, "invalid number in " + value, null, value);
  		}
  	}
  
  	private short[] toDPT(long milliseconds, short[] dst, int index)
  	{
  		synchronized (DPTXlatorTime.class) {
  			getCalendar().clear();
  			c.setTimeInMillis(milliseconds);
  			final int dow = c.get(Calendar.DAY_OF_WEEK);
  			set(dow == Calendar.SUNDAY ? 7 : dow - 1, c
  				.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), c
  				.get(Calendar.SECOND), dst, index);
  		}
  		return dst;
  	}
  
  	private short[] set(int dow, int hour, int minute, int second, short[] dst, int index)
  	{
  		if (dow < 0 || dow > 7)
  			throw new KNXIllegalArgumentException("day of week out of range [0..7]");
  		if (hour < 0 || hour > 23)
  			throw new KNXIllegalArgumentException("hour out of range [0..23]");
  		if (minute < 0 || minute > 59)
  			throw new KNXIllegalArgumentException("minute out of range [0..59]");
  		if (second < 0 || second > 59)
  			throw new KNXIllegalArgumentException("second out of range [0..59]");
  		final int i = 3 * index;
  		dst[i + DOW] = (short) (dow << 5 | hour);
  		dst[i + MINUTE] = (short) minute;
  		dst[i + SECOND] = (short) second;
  		return dst;
  	}
  
  	private int getDOW(String dow) throws KNXFormatException
  	{
  		for (int i = 0; i < DAYS.length; ++i)
  			if (DAYS[i].equalsIgnoreCase(dow))
  				return i;
  		throw logThrow(LogLevel.WARN, "invalid day of week " + dow, null, dow);
  	}
  
  	private long parse(String value) throws KNXFormatException
  	{
  		try {
  			return sdf.parse(value).getTime();
  		}
  		catch (final ParseException e) {
  			throw logThrow(LogLevel.WARN, "invalid time format", e.getMessage(), value);
  		}
  	}
  
  	private static String align(int number)
  	{
  		return number > 9 ? "" : "0";
  	}
  
  	private static Calendar getCalendar()
  	{
  		// don't need to synchronize, it's harmless if we have 2 instances
  		// and we synchronize on class anyway
  		if (c == null) {
  			final Calendar calendar = Calendar.getInstance();
  			calendar.setLenient(false);
  			c = calendar;
  		}
  		return c;
  	}
  }