Review ask

As a clinical trial statistician or programmer, answer three short questions in Your review: the task, the inputs and outputs, and the AI-assisted review. Agreeing with all three approves this benchmark; disagreeing with any needs a comment. Propose a fix with the Edit button on any source file, or add it to your comments.

We suggest spending no more than 5 minutes on a review. The other tabs beside Your review are background for assessment, not under review.

Summary

Lifecycle: reviewedEditUnder review
What this benchmark means
README.md

Public entries: Python and R. Passing coverage requires an installed inventory.

Goal: select each subject's actual treatment (TRT01A), the first and last exposure dates and times (TRTSDT, TRTSDTM, TRTEDT, TRTEDTM), the imputation flags (TRTSTMF, TRTETMF), the treatment duration in days (TRTDURD), and the safety population flag (SAFFL).

Input: one demographics (DM) record per subject carrying the actual arm (ACTARM), plus exposure (EX) records carrying the treatment name (EXTRT), sequence number (EXSEQ), start date (EXSTDTC), and end date (EXENDTC). Records are built from the demographics records, so an exposure record with no matching demographics record adds no record.

Variables:

  • TRT01A: treatment actually received, uppercased: the treatment of the earliest qualifying exposure (a qualifying record names VITAMIN D3 or PLACEBO and carries a start), with ties on the start broken by the lower EXSEQ; then the actual arm (ACTARM) when no exposure qualifies; then the text NOT TREATED when neither source names a treatment.
  • TRTSDT and TRTSDTM: date and date/time of the earliest qualifying exposure start, compared as dates and times rather than as text; a start collected without a time uses 00:00:00, and a start collected without its day is passed over. Both are blank when the subject has no qualifying exposure record with a full start date.
  • TRTSTMF: which part of the first exposure start's time was imputed: H when the start was collected without a time, M when it stops at the hour and S when it stops at the minute; blank when the time was collected to the second or there is no start.
  • TRTEDT and TRTEDTM: date and date/time of the latest exposure end among VITAMIN D3 and PLACEBO records (a record need not have a start to name an end); an end collected without a time uses 23:59:59, and an end collected without its day is passed over. Both are blank when no such record has an end with a full date.
  • TRTETMF: which part of the last exposure end's time was imputed, as for TRTSTMF; blank when the time was collected to the second or there is no end.
  • TRTDURD: number of days from TRTSDT to TRTEDT, counting both the first and the last day (inclusive), so a single treatment day gives one; blank when either date is blank.
  • SAFFL: Y when the subject has a treatment start date, N otherwise (never blank).

Note: the exposure dates, date/times, and duration are all present or all blank together; the latest end can come from a record whose start was never collected.

Inputs

Under review
2 source files

input/dm.csv

Edit
8 rows
input/dm.csv
STUDYIDUSUBJIDACTARM
YAMAA-01Vitamin D3
YAMAA-01Placebo
YAMAA-01Vitamin D3
YAMAA-01Placebo
YAMAA-01Vitamin D3
YAMAA-01—
YAMAA-01Vitamin D3
YAMAA-01Placebo

input/ex.csv

Edit
13 rows
input/ex.csv
STUDYIDUSUBJIDEXSEQEXTRTEXDOSEEXSTDTCEXENDTC
YAMAA-011VITAMIN D340002025-01-082025-01-14T18:00:00
YAMAA-012VITAMIN D340002025-01-15T08:00:002025-01-28
YAMAA-011PLACEBO02025-02-08T09:00:002025-02-14T17:00:00
YAMAA-012PLACEBO02025-02-15T09:00:002025-02-28T17:00:00
YAMAA-011VITAMIN D340002025-03-052025-03-05
YAMAA-011VITAMIN D340002025-04-03T10:00:002025-04-10
YAMAA-012PLACEBO02025-04-03T10:00:002025-04-16T12:00:00
YAMAA-011RESCUE MED2002025-05-012025-05-07
YAMAA-011VITAMIN D340002025-06-08T09:00:002025-06-14T16:00:00
YAMAA-012VITAMIN D34000—2025-06-20
YAMAA-011PLACEBO02025-07-01T10:00:002025-07-07T10:00:00
YAMAA-012PLACEBO02025-07-01T10:00:002025-07-07T10:00:00
YAMAA-011VITAMIN D340002025-03-08T10:00:002025-03-21T16:00:00

Expected output

Under review
8 expected rows

expected/adsl.csv

Edit
8 rows
expected/adsl.csv
STUDYIDUSUBJIDTRT01ATRTSDTTRTSDTMTRTSTMFTRTEDTTRTEDTMTRTETMFTRTDURDSAFFL
YAMAA-01VITAMIN D32025-01-082025-01-08T00:00:00H2025-01-282025-01-28T23:59:59H21Y
YAMAA-01PLACEBO2025-02-082025-02-08T09:00:00—2025-02-282025-02-28T17:00:00—21Y
YAMAA-01VITAMIN D32025-03-052025-03-05T00:00:00H2025-03-052025-03-05T23:59:59H1Y
YAMAA-01VITAMIN D32025-04-032025-04-03T10:00:00—2025-04-162025-04-16T12:00:00—14Y
YAMAA-01VITAMIN D3———————N
YAMAA-01NOT TREATED———————N
YAMAA-01VITAMIN D32025-06-082025-06-08T09:00:00—2025-06-202025-06-20T23:59:59H13Y
YAMAA-01PLACEBO2025-07-012025-07-01T10:00:00—2025-07-072025-07-07T10:00:00—7Y
Shaded columns are derived— = missing value

Human review and assessment

Your review

3 questions and your comments · View benchmark discussions

Mapping spec

Generated from the benchmark YAML; do not edit by hand

Dataset NameVariable NameVariable LabelTypeCodelist/Controlled TermsCoreComputational MethodOrigin
ADSLSTUDYIDStudy IdentifiercharacterCopy value from DM.STUDYID.Predecessor
ADSLUSUBJIDUnique Subject IdentifiercharacterCopy value from DM.USUBJID.Predecessor
ADSLTRT01AActual Treatment for Period 01characterVITAMIN D3, PLACEBO, NOT TREATEDConvert TRT01SRC to upper case.Derived
ADSLTRTSDTMDatetime of First Exposure to TreatmentnumericISO 8601Aggregate MIN(EXSTDTM) over records matching on the shared output keys, where EX.EXTRT IN ('VITAMIN D3', 'PLACEBO') AND EX.EXSTDTC IS NOT NULL, with EXSTDTM as impute incomplete datetime from EX.EXSTDTC, giving each time part the source lacks its earliest value; a source without a complete date gives blank; invalid text → blank.Derived
ADSLTRTSTMFTime of First Exposure Imputation FlagcharacterH, M, STime imputation flag for TRTSDTM: "H" when the whole time was imputed, "M" when the minutes and seconds were, "S" when only the seconds were; blank when the time was collected to the second.Derived
ADSLTRTEDTMDatetime of Last Exposure to TreatmentnumericISO 8601Aggregate MAX(EXENDTM) over records matching on the shared output keys, where EX.EXTRT IN ('VITAMIN D3', 'PLACEBO') AND EX.EXENDTC IS NOT NULL, with EXENDTM as impute incomplete datetime from EX.EXENDTC, giving each time part the source lacks its latest value; a source without a complete date gives blank; invalid text → blank.Derived
ADSLTRTETMFTime of Last Exposure Imputation FlagcharacterH, M, STime imputation flag for TRTEDTM: "H" when the whole time was imputed, "M" when the minutes and seconds were, "S" when only the seconds were; blank when the time was collected to the second.Derived
ADSLTRTSDTDate of First Exposure to TreatmentnumericISO 8601Take the date part of TRTSDTM, blank for a year or a year and month alone.Derived
ADSLTRTEDTDate of Last Exposure to TreatmentnumericISO 8601Take the date part of TRTEDTM, blank for a year or a year and month alone.Derived
ADSLTRTDURDTotal Treatment Duration (Days)numericWhole days from TRTSDT to TRTEDT, counting both endpoints.Derived
ADSLSAFFLSafety Population FlagcharacterY, N"Y" when TRTSDT IS NOT NULL; "N" otherwise; "N" when the condition is unknown.Derived
VariablePermitted values
TRT01AVITAMIN D3, PLACEBO, NOT TREATED
TRTSTMFH, M, S
TRTETMFH, M, S
SAFFLY, N
VersionDateAuthorDescriptionReviewerSign-off
1.72026-10-20yamaa docs buildRead a specification in the 1.0 surface as its 0.5 counterpart; state that missing values stay missing where a mapping declares no missing handler, and leave out a declared missing answer that restates a handler's default
1.62026-10-17yamaa docs buildDescribe collected date parts written as ISO 8601 date text and times of day counted in seconds since midnight
1.52026-10-17yamaa docs buildName collected precision in words instead of letter codes; state imputation fallbacks, minimum source precision, bounds ignored outside the collected period, and invalid text with no handler as an error; describe date and datetime shifts, imputation flag codes, and partial text giving no date part
1.42026-10-15yamaa docs buildState datetime precision codes through the hour and minute, and complete only the time parts a collected datetime lacks
1.32026-09-29yamaa docs buildShow study codelist names, external dictionaries, and ISO 8601 formats in variable rows; list the document's codelist values and metadata
1.22026-09-29yamaa docs buildClassify ADaM copies from a declared input as Predecessor and recodes as Derived, and SDTM recodes of locally derived columns as Derived
1.12026-09-29yamaa docs buildResolve lookups into the donor record they select, and give every derivation shape a plain-language rule instead of its raw YAML
1.0yamaa docs buildInitial generation from spec.yaml

Agent prompt

The request an agent receives with the input files; each tier states no more than the one above

prompts/adam-adsl-treatment/full.md

Edit
40 lines

Following CDISC ADaM standards, use the provided DM and EX datasets to create an ADSL dataset with one record per subject.

The output dataset should contain the following columns in this order: STUDYID, USUBJID, TRT01A, TRTSDT, TRTSDTM, TRTSTMF, TRTEDT, TRTEDTM, TRTETMF, TRTDURD, SAFFL

TRT01A is the treatment actually received, in upper case. TRT01A is the treatment named by the subject's earliest qualifying exposure record, where a qualifying record names "VITAMIN D3" or "PLACEBO" as its treatment and carries a start date/time, and records with the same start are ordered by the lower EXSEQ. When no exposure record qualifies, TRT01A is the subject's actual arm (ACTARM). When neither an exposure record nor the actual arm names a treatment, TRT01A is "NOT TREATED". TRTSDT is the date of the earliest qualifying exposure start, and TRTSDTM is that start as a date and time, with the date and time joined by a T and a start collected without a time given the time 00:00:00. TRTSDT and TRTSDTM have no value when the subject has no qualifying exposure record. TRTSTMF records which part of the first exposure start's time was supplied: "H" when the start was collected without a time, "M" when its time stops at the hour, and "S" when its time stops at the minute. TRTSTMF has no value when that time was collected to the second or when there is no start. TRTEDT is the date of the latest exposure end among the subject's records naming "VITAMIN D3" or "PLACEBO", whether or not that record carries a start, and TRTEDTM is that end as a date and time, with the date and time joined by a T and an end collected without a time given the time 23:59:59. TRTEDT and TRTEDTM have no value when no record naming "VITAMIN D3" or "PLACEBO" has an end. TRTETMF records which part of the last exposure end's time was supplied, as TRTSTMF does for the start, and has no value when that time was collected to the second or when there is no end. TRTDURD is the number of days from TRTSDT to TRTEDT counting both the first and the last day, so a single treatment day gives one, and it has no value when either date has no value. SAFFL is "Y" when the subject has a treatment start date (TRTSDT) and "N" otherwise, and it always has a value. The start and end dates and times and the duration are either all present or all have no value together.

Read the source datasets from /app/input and save the completed dataset as /app/output/adsl.csv.

prompts/adam-adsl-treatment/conventions.md

Edit
18 lines

Following CDISC ADaM standards, use the provided DM and EX datasets to create an ADSL dataset with one record per subject.

The output dataset should contain the following columns in this order: STUDYID, USUBJID, TRT01A, TRTSDT, TRTSDTM, TRTSTMF, TRTEDT, TRTEDTM, TRTETMF, TRTDURD, SAFFL

TRT01A is "VITAMIN D3", "PLACEBO", the subject's actual arm (ACTARM), or "NOT TREATED", in upper case. TRTSDTM is a date and time with the date and time joined by a T, and a start collected without a time given the time 00:00:00. TRTEDTM is a date and time with the date and time joined by a T, and an end collected without a time given the time 23:59:59. TRTSTMF is "H", "M" or "S", or has no value. TRTETMF is "H", "M" or "S", or has no value. TRTDURD is the number of days from TRTSDT to TRTEDT counting both the first and the last day, so a single treatment day gives one. SAFFL is "Y" or "N".

Read the source datasets from /app/input and save the completed dataset as /app/output/adsl.csv.

prompts/adam-adsl-treatment/brief.md

Edit
9 lines

Following CDISC ADaM standards, use the provided DM and EX datasets to create an ADSL dataset with one record per subject.

The output dataset should contain the following columns in this order: STUDYID, USUBJID, TRT01A, TRTSDT, TRTSDTM, TRTSTMF, TRTEDT, TRTEDTM, TRTETMF, TRTDURD, SAFFL

Read the source datasets from /app/input and save the completed dataset as /app/output/adsl.csv.

yamaa code

Public calls generated from benchmark.yaml; results must match the expected output

R

Edit
3 lines
library(yamaa)yamaa_spec("spec.yaml")$run()$output

Python

Edit
3 lines
import yamaayamaa.spec("spec.yaml").run().output

Solution without yamaa

Written from the full prompt and the inputs alone; CI checks it reproduces the expected output

solutions/adam-adsl-treatment/result.R

Edit
80 lines
# Reference solution for the yamaa benchmark adam-adsl-treatment (R track).## Written from the benchmark's full prompt and its inputs alone, as an agent# would write it. Harbor's oracle agent runs it to check that the prompt can# be solved and that the grader scores a correct answer 1.library(dplyr, warn.conflicts = FALSE)library(readr)library(stringr)library(lubridate)dm <- read_csv(  "/app/input/dm.csv",  col_types = cols(.default = col_character()))ex <- read_csv(  "/app/input/ex.csv",  col_types = cols(EXSEQ = col_integer(), .default = col_character()))qual <- c("VITAMIN D3", "PLACEBO")parse_start <- function(x) {  x[!is.na(x) & x == ""] <- NA_character_  dt <- suppressWarnings(ymd_hms(x, quiet = TRUE, tz = "UTC"))  d <- suppressWarnings(ymd(x, quiet = TRUE, tz = "UTC"))  coalesce(dt, as.POSIXct(d, tz = "UTC"))}parse_end <- function(x) {  base <- parse_start(x)  is_date <- !is.na(x) & x != "" & !str_detect(x, "T")  base[is_date] <- base[is_date] + 23 * 3600 + 59 * 60 + 59  base}ex_dt <- ex |>  mutate(    `__start_dt` = parse_start(EXSTDTC),    `__end_dt` = parse_end(EXENDTC)  )first_start <- ex_dt |>  filter(EXTRT %in% qual, !is.na(`__start_dt`)) |>  arrange(`__start_dt`, EXSEQ) |>  distinct(STUDYID, USUBJID, .keep_all = TRUE) |>  select(STUDYID, USUBJID, TRT01RAW = EXTRT, `__stdtm` = `__start_dt`, `__stdtc` = EXSTDTC)last_end <- ex_dt |>  filter(EXTRT %in% qual, !is.na(`__end_dt`)) |>  arrange(desc(`__end_dt`)) |>  distinct(STUDYID, USUBJID, .keep_all = TRUE) |>  select(STUDYID, USUBJID, `__endtm` = `__end_dt`, `__endtc` = EXENDTC)adsl <- dm |>  left_join(first_start, by = c("STUDYID", "USUBJID")) |>  left_join(last_end, by = c("STUDYID", "USUBJID")) |>  mutate(    `__src` = coalesce(TRT01RAW, ACTARM),    TRT01A = case_when(      is.na(`__src`) | `__src` == "" ~ "NOT TREATED",      .default = str_to_upper(`__src`)    ),    TRTSDTM = format(`__stdtm`, "%Y-%m-%dT%H:%M:%S", tz = "UTC"),    TRTSDT = as.Date(`__stdtm`, tz = "UTC"),    TRTSTMF = if_else(!is.na(`__stdtc`) & !str_detect(`__stdtc`, "T"), "H", NA_character_),    TRTEDTM = format(`__endtm`, "%Y-%m-%dT%H:%M:%S", tz = "UTC"),    TRTEDT = as.Date(`__endtm`, tz = "UTC"),    TRTETMF = if_else(!is.na(`__endtc`) & !str_detect(`__endtc`, "T"), "H", NA_character_),    TRTDURD = as.integer(TRTEDT - TRTSDT) + 1L,    SAFFL = if_else(is.na(TRTSDT), "N", "Y")  ) |>  select(    STUDYID, USUBJID, TRT01A, TRTSDT, TRTSDTM, TRTSTMF,    TRTEDT, TRTEDTM, TRTETMF, TRTDURD, SAFFL  ) |>  arrange(USUBJID)dir.create("/app/output", showWarnings = FALSE)write_csv(adsl, "/app/output/adsl.csv", na = "")

solutions/adam-adsl-treatment/result.py

Edit
158 lines
# Reference solution for the yamaa benchmark adam-adsl-treatment (Python track).## Written from the benchmark's full prompt and its inputs alone, as an agent# would write it. Harbor's oracle agent runs it to check that the prompt can# be solved and that the grader scores a correct answer 1."""Build ADSL (one record per subject) from DM and EX.Reads /app/input/dm.csv and /app/input/ex.csv and writes/app/output/adsl.csv with columns:STUDYID, USUBJID, TRT01A, TRTSDT, TRTSDTM, TRTSTMF, TRTEDT, TRTEDTM,TRTETMF, TRTDURD, SAFFL"""import csvfrom datetime import datetime, timeINPUT_DIR = "/app/input"OUTPUT_PATH = "/app/output/adsl.csv"NAMED_TREATMENTS = {"VITAMIN D3", "PLACEBO"}COLUMNS = [    "STUDYID",    "USUBJID",    "TRT01A",    "TRTSDT",    "TRTSDTM",    "TRTSTMF",    "TRTEDT",    "TRTEDTM",    "TRTETMF",    "TRTDURD",    "SAFFL",]def parse_dtc(value):    """Split an ISO 8601 date/time collection value.    Returns (date, time_or_None, has_value). A value without a "T"    separator was collected as a date only.    """    value = (value or "").strip()    if not value:        return None, None, False    if "T" in value:        date_part, time_part = value.split("T", 1)        parsed_time = datetime.strptime(time_part.strip(), "%H:%M:%S").time()        return (            datetime.strptime(date_part.strip(), "%Y-%m-%d").date(),            parsed_time,            True,        )    return datetime.strptime(value, "%Y-%m-%d").date(), None, Truedef read_rows(path):    with open(path, newline="") as handle:        return list(csv.DictReader(handle))def main():    dm_rows = read_rows(f"{INPUT_DIR}/dm.csv")    ex_rows = read_rows(f"{INPUT_DIR}/ex.csv")    ex_by_subject = {}    for row in ex_rows:        ex_by_subject.setdefault(row["USUBJID"], []).append(row)    output_rows = []    for dm in dm_rows:        subject_ex = ex_by_subject.get(dm["USUBJID"], [])        # Qualifying exposure records: named treatment and a start value.        qualifying = []        for row in subject_ex:            if row["EXTRT"].strip() not in NAMED_TREATMENTS:                continue            start_date, start_time, has_start = parse_dtc(row["EXSTDTC"])            if has_start:                effective = datetime.combine(                    start_date, start_time or time(0, 0, 0)                )                qualifying.append(                    (effective, int(row["EXSEQ"]), row, start_date, start_time)                )        qualifying.sort(key=lambda item: (item[0], item[1]))        trtsdt = trtsdtm = trtstmf = ""        trtedt = trtedtm = trtetmf = ""        trtdurd = ""        if qualifying:            _, _, first_row, start_date, start_time = qualifying[0]            trt01a = first_row["EXTRT"].strip().upper()            trtsdt = start_date.isoformat()            trtsdtm = (                f"{start_date.isoformat()}T"                f"{(start_time or time(0, 0, 0)).isoformat()}"            )            trtstmf = "H" if start_time is None else ""        else:            actarm = (dm.get("ACTARM") or "").strip()            trt01a = actarm.upper() if actarm else "NOT TREATED"        # Latest end among records naming a treatment, with or without a        # start; an end collected without a time counts as 23:59:59.        end_candidates = []        for row in subject_ex:            if row["EXTRT"].strip() not in NAMED_TREATMENTS:                continue            end_date, end_time, has_end = parse_dtc(row["EXENDTC"])            if has_end:                effective = datetime.combine(                    end_date, end_time or time(23, 59, 59)                )                end_candidates.append((effective, end_date, end_time))        if end_candidates:            _, end_date, end_time = max(                end_candidates, key=lambda item: item[0]            )            trtedt = end_date.isoformat()            trtedtm = (                f"{end_date.isoformat()}T"                f"{(end_time or time(23, 59, 59)).isoformat()}"            )            trtetmf = "H" if end_time is None else ""        if trtsdt and trtedt:            start = datetime.strptime(trtsdt, "%Y-%m-%d").date()            end = datetime.strptime(trtedt, "%Y-%m-%d").date()            trtdurd = str((end - start).days + 1)        output_rows.append(            {                "STUDYID": dm["STUDYID"],                "USUBJID": dm["USUBJID"],                "TRT01A": trt01a,                "TRTSDT": trtsdt,                "TRTSDTM": trtsdtm,                "TRTSTMF": trtstmf,                "TRTEDT": trtedt,                "TRTEDTM": trtedtm,                "TRTETMF": trtetmf,                "TRTDURD": trtdurd,                "SAFFL": "Y" if trtsdt else "N",            }        )    with open(OUTPUT_PATH, "w", newline="") as handle:        writer = csv.DictWriter(handle, fieldnames=COLUMNS)        writer.writeheader()        writer.writerows(output_rows)if __name__ == "__main__":    main()

solutions/adam-adsl-treatment/result.sas

Edit
50 lines
/* opensas reference solution for the yamaa benchmark adam-adsl-treatment.   Reads the benchmark inputs and derives the requested output.   Execute with the existing opensas runtime: opensas /app/output/result.sas. */data dm;  length STUDYID USUBJID ACTARM $1024;  infile "/app/input/dm.csv" dsd dlm="," firstobs=2 truncover lrecl=32767;  input STUDYID : $char1024. USUBJID : $char1024. ACTARM : $char1024.;run;data ex;  length STUDYID USUBJID EXTRT EXSTDTC EXENDTC $1024;  infile "/app/input/ex.csv" dsd dlm="," firstobs=2 truncover lrecl=32767;  input STUDYID : $char1024. USUBJID : $char1024. EXSEQ EXTRT : $char1024. EXDOSE EXSTDTC : $char1024. EXENDTC : $char1024.;run;data exposure;  length startmoment endmoment $19;  set ex;  if upcase(EXTRT) in ('VITAMIN D3','PLACEBO');  startmoment=EXSTDTC; endmoment=EXENDTC;  if lengthn(EXSTDTC)=10 then startmoment=cats(EXSTDTC,'T00:00:00');  else if lengthn(EXSTDTC)=16 then startmoment=cats(EXSTDTC,':00');  if lengthn(EXENDTC)=10 then endmoment=cats(EXENDTC,'T23:59:59');  else if lengthn(EXENDTC)=16 then endmoment=cats(EXENDTC,':00');run;proc sort data=exposure(where=(EXSTDTC ne '')) out=starts; by STUDYID USUBJID startmoment EXSEQ; run;data firstex; set starts; by STUDYID USUBJID; if first.USUBJID; run;proc sort data=exposure(where=(EXENDTC ne '')) out=ends; by STUDYID USUBJID descending endmoment; run;data lastex; set ends; by STUDYID USUBJID; if first.USUBJID; run;proc sql; create table joined as select a.*,b.EXTRT,b.EXSTDTC,b.startmoment,c.EXENDTC,c.endmoment from dm as a  left join firstex as b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID left join lastex as c on a.STUDYID=c.STUDYID and a.USUBJID=c.USUBJID; quit;data result;  length TRT01A $1024 TRTSDT TRTEDT $10 TRTSDTM TRTEDTM $19 TRTSTMF TRTETMF SAFFL $1;  set joined;  TRT01A=upcase(coalescec(EXTRT,ACTARM,'NOT TREATED'));  TRTSDT=''; TRTEDT=''; TRTSTMF=''; TRTETMF=''; TRTDURD=.;  if lengthn(EXSTDTC)>=10 then TRTSDT=substr(EXSTDTC,1,10);  if lengthn(EXENDTC)>=10 then TRTEDT=substr(EXENDTC,1,10);  TRTSDTM=tranwrd(startmoment,'T',' '); TRTEDTM=tranwrd(endmoment,'T',' ');  if lengthn(EXSTDTC)=10 then TRTSTMF='H';  if lengthn(EXENDTC)=10 then TRTETMF='H';  if not missing(TRTSDT) and not missing(TRTEDT) then TRTDURD=input(TRTEDT,yymmdd10.)-input(TRTSDT,yymmdd10.)+1;  SAFFL='N'; if not missing(TRTSDT) then SAFFL='Y';run;proc sql;  create table final as select STUDYID, USUBJID, TRT01A, TRTSDT, TRTSDTM, TRTSTMF, TRTEDT, TRTEDTM, TRTETMF, TRTDURD, SAFFL from result;quit;proc export data=final outfile="/app/output/adsl.csv" dbms=csv replace; run;