code: private static Object getCsvValue(Object apiValue) {
      if (apiValue == null) {
        return null;
      } else if (apiValue instanceof DateTime) {
        return DateTimes.toStringWithTimeZone((DateTime) apiValue);
      } else if (apiValue instanceof Date) {
        return DateTimes.toString((Date) apiValue);
      } else if (apiValue instanceof Set<?>) {
        Set<Object> csvValues = new LinkedHashSet<Object>();
        for (Object entry : (Set<?>) apiValue) {
          Object csvValue = getCsvValue(entry);
          validateSetValueEntryForSet(csvValue, csvValues);
          if (csvValue instanceof String) {
            csvValue = StringEscapeUtils.escapeCsv((String) csvValue);
          }
          csvValues.add(csvValue);
        }
        return Joiner.on(",").join(csvValues);
      } else if (apiValue instanceof Targeting) {
        throw new IllegalArgumentException("Unsupported Value type [" + apiValue.getClass() + "]");
      } else {
        return apiValue;
      }
    }
docs: Gets the underlying value of the {@code Value} object that should be used for CSV conversion
  (i.e. DateTimeValue will return a String representation, but NumberValue will return a Long or
  Double).
  
  @param apiValue the api value to convert
  @return the CSV conversion value of the api value or {@code null} if the underlying value is
  null
  @throws IllegalArgumentException if value cannot be converted